addr_linux.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. package netlink
  2. import (
  3. "fmt"
  4. "net"
  5. "strings"
  6. "syscall"
  7. "github.com/vishvananda/netlink/nl"
  8. "github.com/vishvananda/netns"
  9. "golang.org/x/sys/unix"
  10. )
  11. // IFA_FLAGS is a u32 attribute.
  12. const IFA_FLAGS = 0x8
  13. // AddrAdd will add an IP address to a link device.
  14. // Equivalent to: `ip addr add $addr dev $link`
  15. func AddrAdd(link Link, addr *Addr) error {
  16. return pkgHandle.AddrAdd(link, addr)
  17. }
  18. // AddrAdd will add an IP address to a link device.
  19. // Equivalent to: `ip addr add $addr dev $link`
  20. func (h *Handle) AddrAdd(link Link, addr *Addr) error {
  21. req := h.newNetlinkRequest(unix.RTM_NEWADDR, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
  22. return h.addrHandle(link, addr, req)
  23. }
  24. // AddrReplace will replace (or, if not present, add) an IP address on a link device.
  25. // Equivalent to: `ip addr replace $addr dev $link`
  26. func AddrReplace(link Link, addr *Addr) error {
  27. return pkgHandle.AddrReplace(link, addr)
  28. }
  29. // AddrReplace will replace (or, if not present, add) an IP address on a link device.
  30. // Equivalent to: `ip addr replace $addr dev $link`
  31. func (h *Handle) AddrReplace(link Link, addr *Addr) error {
  32. req := h.newNetlinkRequest(unix.RTM_NEWADDR, unix.NLM_F_CREATE|unix.NLM_F_REPLACE|unix.NLM_F_ACK)
  33. return h.addrHandle(link, addr, req)
  34. }
  35. // AddrDel will delete an IP address from a link device.
  36. // Equivalent to: `ip addr del $addr dev $link`
  37. func AddrDel(link Link, addr *Addr) error {
  38. return pkgHandle.AddrDel(link, addr)
  39. }
  40. // AddrDel will delete an IP address from a link device.
  41. // Equivalent to: `ip addr del $addr dev $link`
  42. func (h *Handle) AddrDel(link Link, addr *Addr) error {
  43. req := h.newNetlinkRequest(unix.RTM_DELADDR, unix.NLM_F_ACK)
  44. return h.addrHandle(link, addr, req)
  45. }
  46. func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error {
  47. base := link.Attrs()
  48. if addr.Label != "" && !strings.HasPrefix(addr.Label, base.Name) {
  49. return fmt.Errorf("label must begin with interface name")
  50. }
  51. h.ensureIndex(base)
  52. family := nl.GetIPFamily(addr.IP)
  53. msg := nl.NewIfAddrmsg(family)
  54. msg.Index = uint32(base.Index)
  55. msg.Scope = uint8(addr.Scope)
  56. mask := addr.Mask
  57. if addr.Peer != nil {
  58. mask = addr.Peer.Mask
  59. }
  60. prefixlen, masklen := mask.Size()
  61. msg.Prefixlen = uint8(prefixlen)
  62. req.AddData(msg)
  63. var localAddrData []byte
  64. if family == FAMILY_V4 {
  65. localAddrData = addr.IP.To4()
  66. } else {
  67. localAddrData = addr.IP.To16()
  68. }
  69. localData := nl.NewRtAttr(unix.IFA_LOCAL, localAddrData)
  70. req.AddData(localData)
  71. var peerAddrData []byte
  72. if addr.Peer != nil {
  73. if family == FAMILY_V4 {
  74. peerAddrData = addr.Peer.IP.To4()
  75. } else {
  76. peerAddrData = addr.Peer.IP.To16()
  77. }
  78. } else {
  79. peerAddrData = localAddrData
  80. }
  81. addressData := nl.NewRtAttr(unix.IFA_ADDRESS, peerAddrData)
  82. req.AddData(addressData)
  83. if addr.Flags != 0 {
  84. if addr.Flags <= 0xff {
  85. msg.IfAddrmsg.Flags = uint8(addr.Flags)
  86. } else {
  87. b := make([]byte, 4)
  88. native.PutUint32(b, uint32(addr.Flags))
  89. flagsData := nl.NewRtAttr(IFA_FLAGS, b)
  90. req.AddData(flagsData)
  91. }
  92. }
  93. if family == FAMILY_V4 {
  94. if addr.Broadcast == nil {
  95. calcBroadcast := make(net.IP, masklen/8)
  96. for i := range localAddrData {
  97. calcBroadcast[i] = localAddrData[i] | ^mask[i]
  98. }
  99. addr.Broadcast = calcBroadcast
  100. }
  101. req.AddData(nl.NewRtAttr(unix.IFA_BROADCAST, addr.Broadcast))
  102. if addr.Label != "" {
  103. labelData := nl.NewRtAttr(unix.IFA_LABEL, nl.ZeroTerminated(addr.Label))
  104. req.AddData(labelData)
  105. }
  106. }
  107. // 0 is the default value for these attributes. However, 0 means "expired", while the least-surprising default
  108. // value should be "forever". To compensate for that, only add the attributes if at least one of the values is
  109. // non-zero, which means the caller has explicitly set them
  110. if addr.ValidLft > 0 || addr.PreferedLft > 0 {
  111. cachedata := nl.IfaCacheInfo{
  112. IfaValid: uint32(addr.ValidLft),
  113. IfaPrefered: uint32(addr.PreferedLft),
  114. }
  115. req.AddData(nl.NewRtAttr(unix.IFA_CACHEINFO, cachedata.Serialize()))
  116. }
  117. _, err := req.Execute(unix.NETLINK_ROUTE, 0)
  118. return err
  119. }
  120. // AddrList gets a list of IP addresses in the system.
  121. // Equivalent to: `ip addr show`.
  122. // The list can be filtered by link and ip family.
  123. func AddrList(link Link, family int) ([]Addr, error) {
  124. return pkgHandle.AddrList(link, family)
  125. }
  126. // AddrList gets a list of IP addresses in the system.
  127. // Equivalent to: `ip addr show`.
  128. // The list can be filtered by link and ip family.
  129. func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
  130. req := h.newNetlinkRequest(unix.RTM_GETADDR, unix.NLM_F_DUMP)
  131. msg := nl.NewIfInfomsg(family)
  132. req.AddData(msg)
  133. msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWADDR)
  134. if err != nil {
  135. return nil, err
  136. }
  137. indexFilter := 0
  138. if link != nil {
  139. base := link.Attrs()
  140. h.ensureIndex(base)
  141. indexFilter = base.Index
  142. }
  143. var res []Addr
  144. for _, m := range msgs {
  145. addr, msgFamily, ifindex, err := parseAddr(m)
  146. if err != nil {
  147. return res, err
  148. }
  149. if link != nil && ifindex != indexFilter {
  150. // Ignore messages from other interfaces
  151. continue
  152. }
  153. if family != FAMILY_ALL && msgFamily != family {
  154. continue
  155. }
  156. res = append(res, addr)
  157. }
  158. return res, nil
  159. }
  160. func parseAddr(m []byte) (addr Addr, family, index int, err error) {
  161. msg := nl.DeserializeIfAddrmsg(m)
  162. family = -1
  163. index = -1
  164. attrs, err1 := nl.ParseRouteAttr(m[msg.Len():])
  165. if err1 != nil {
  166. err = err1
  167. return
  168. }
  169. family = int(msg.Family)
  170. index = int(msg.Index)
  171. var local, dst *net.IPNet
  172. for _, attr := range attrs {
  173. switch attr.Attr.Type {
  174. case unix.IFA_ADDRESS:
  175. dst = &net.IPNet{
  176. IP: attr.Value,
  177. Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
  178. }
  179. case unix.IFA_LOCAL:
  180. // iproute2 manual:
  181. // If a peer address is specified, the local address
  182. // cannot have a prefix length. The network prefix is
  183. // associated with the peer rather than with the local
  184. // address.
  185. n := 8 * len(attr.Value)
  186. local = &net.IPNet{
  187. IP: attr.Value,
  188. Mask: net.CIDRMask(n, n),
  189. }
  190. case unix.IFA_BROADCAST:
  191. addr.Broadcast = attr.Value
  192. case unix.IFA_LABEL:
  193. addr.Label = string(attr.Value[:len(attr.Value)-1])
  194. case IFA_FLAGS:
  195. addr.Flags = int(native.Uint32(attr.Value[0:4]))
  196. case nl.IFA_CACHEINFO:
  197. ci := nl.DeserializeIfaCacheInfo(attr.Value)
  198. addr.PreferedLft = int(ci.IfaPrefered)
  199. addr.ValidLft = int(ci.IfaValid)
  200. }
  201. }
  202. // libnl addr.c comment:
  203. // IPv6 sends the local address as IFA_ADDRESS with no
  204. // IFA_LOCAL, IPv4 sends both IFA_LOCAL and IFA_ADDRESS
  205. // with IFA_ADDRESS being the peer address if they differ
  206. //
  207. // But obviously, as there are IPv6 PtP addresses, too,
  208. // IFA_LOCAL should also be handled for IPv6.
  209. if local != nil {
  210. if family == FAMILY_V4 && local.IP.Equal(dst.IP) {
  211. addr.IPNet = dst
  212. } else {
  213. addr.IPNet = local
  214. addr.Peer = dst
  215. }
  216. } else {
  217. addr.IPNet = dst
  218. }
  219. addr.Scope = int(msg.Scope)
  220. return
  221. }
  222. type AddrUpdate struct {
  223. LinkAddress net.IPNet
  224. LinkIndex int
  225. Flags int
  226. Scope int
  227. PreferedLft int
  228. ValidLft int
  229. NewAddr bool // true=added false=deleted
  230. }
  231. // AddrSubscribe takes a chan down which notifications will be sent
  232. // when addresses change. Close the 'done' chan to stop subscription.
  233. func AddrSubscribe(ch chan<- AddrUpdate, done <-chan struct{}) error {
  234. return addrSubscribeAt(netns.None(), netns.None(), ch, done, nil, false)
  235. }
  236. // AddrSubscribeAt works like AddrSubscribe plus it allows the caller
  237. // to choose the network namespace in which to subscribe (ns).
  238. func AddrSubscribeAt(ns netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error {
  239. return addrSubscribeAt(ns, netns.None(), ch, done, nil, false)
  240. }
  241. // AddrSubscribeOptions contains a set of options to use with
  242. // AddrSubscribeWithOptions.
  243. type AddrSubscribeOptions struct {
  244. Namespace *netns.NsHandle
  245. ErrorCallback func(error)
  246. ListExisting bool
  247. }
  248. // AddrSubscribeWithOptions work like AddrSubscribe but enable to
  249. // provide additional options to modify the behavior. Currently, the
  250. // namespace can be provided as well as an error callback.
  251. func AddrSubscribeWithOptions(ch chan<- AddrUpdate, done <-chan struct{}, options AddrSubscribeOptions) error {
  252. if options.Namespace == nil {
  253. none := netns.None()
  254. options.Namespace = &none
  255. }
  256. return addrSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting)
  257. }
  258. func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error {
  259. s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_IPV4_IFADDR, unix.RTNLGRP_IPV6_IFADDR)
  260. if err != nil {
  261. return err
  262. }
  263. if done != nil {
  264. go func() {
  265. <-done
  266. s.Close()
  267. }()
  268. }
  269. if listExisting {
  270. req := pkgHandle.newNetlinkRequest(unix.RTM_GETADDR,
  271. unix.NLM_F_DUMP)
  272. infmsg := nl.NewIfInfomsg(unix.AF_UNSPEC)
  273. req.AddData(infmsg)
  274. if err := s.Send(req); err != nil {
  275. return err
  276. }
  277. }
  278. go func() {
  279. defer close(ch)
  280. for {
  281. msgs, err := s.Receive()
  282. if err != nil {
  283. if cberr != nil {
  284. cberr(err)
  285. }
  286. return
  287. }
  288. for _, m := range msgs {
  289. if m.Header.Type == unix.NLMSG_DONE {
  290. continue
  291. }
  292. if m.Header.Type == unix.NLMSG_ERROR {
  293. native := nl.NativeEndian()
  294. error := int32(native.Uint32(m.Data[0:4]))
  295. if error == 0 {
  296. continue
  297. }
  298. if cberr != nil {
  299. cberr(syscall.Errno(-error))
  300. }
  301. return
  302. }
  303. msgType := m.Header.Type
  304. if msgType != unix.RTM_NEWADDR && msgType != unix.RTM_DELADDR {
  305. if cberr != nil {
  306. cberr(fmt.Errorf("bad message type: %d", msgType))
  307. }
  308. return
  309. }
  310. addr, _, ifindex, err := parseAddr(m.Data)
  311. if err != nil {
  312. if cberr != nil {
  313. cberr(fmt.Errorf("could not parse address: %v", err))
  314. }
  315. return
  316. }
  317. ch <- AddrUpdate{LinkAddress: *addr.IPNet,
  318. LinkIndex: ifindex,
  319. NewAddr: msgType == unix.RTM_NEWADDR,
  320. Flags: addr.Flags,
  321. Scope: addr.Scope,
  322. PreferedLft: addr.PreferedLft,
  323. ValidLft: addr.ValidLft}
  324. }
  325. }
  326. }()
  327. return nil
  328. }