addr_linux.go 12 KB

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