addr_linux.go 12 KB

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