addr_linux.go 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  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. prefixlen, masklen := addr.Mask.Size()
  57. msg.Prefixlen = uint8(prefixlen)
  58. req.AddData(msg)
  59. var localAddrData []byte
  60. if family == FAMILY_V4 {
  61. localAddrData = addr.IP.To4()
  62. } else {
  63. localAddrData = addr.IP.To16()
  64. }
  65. localData := nl.NewRtAttr(unix.IFA_LOCAL, localAddrData)
  66. req.AddData(localData)
  67. var peerAddrData []byte
  68. if addr.Peer != nil {
  69. if family == FAMILY_V4 {
  70. peerAddrData = addr.Peer.IP.To4()
  71. } else {
  72. peerAddrData = addr.Peer.IP.To16()
  73. }
  74. } else {
  75. peerAddrData = localAddrData
  76. }
  77. addressData := nl.NewRtAttr(unix.IFA_ADDRESS, peerAddrData)
  78. req.AddData(addressData)
  79. if addr.Flags != 0 {
  80. if addr.Flags <= 0xff {
  81. msg.IfAddrmsg.Flags = uint8(addr.Flags)
  82. } else {
  83. b := make([]byte, 4)
  84. native.PutUint32(b, uint32(addr.Flags))
  85. flagsData := nl.NewRtAttr(IFA_FLAGS, b)
  86. req.AddData(flagsData)
  87. }
  88. }
  89. if family == FAMILY_V4 {
  90. if addr.Broadcast == nil {
  91. calcBroadcast := make(net.IP, masklen/8)
  92. for i := range localAddrData {
  93. calcBroadcast[i] = localAddrData[i] | ^addr.Mask[i]
  94. }
  95. addr.Broadcast = calcBroadcast
  96. }
  97. req.AddData(nl.NewRtAttr(unix.IFA_BROADCAST, addr.Broadcast))
  98. if addr.Label != "" {
  99. labelData := nl.NewRtAttr(unix.IFA_LABEL, nl.ZeroTerminated(addr.Label))
  100. req.AddData(labelData)
  101. }
  102. }
  103. // 0 is the default value for these attributes. However, 0 means "expired", while the least-surprising default
  104. // value should be "forever". To compensate for that, only add the attributes if at least one of the values is
  105. // non-zero, which means the caller has explicitly set them
  106. if addr.ValidLft > 0 || addr.PreferedLft > 0 {
  107. cachedata := nl.IfaCacheInfo{
  108. IfaValid: uint32(addr.ValidLft),
  109. IfaPrefered: uint32(addr.PreferedLft),
  110. }
  111. req.AddData(nl.NewRtAttr(unix.IFA_CACHEINFO, cachedata.Serialize()))
  112. }
  113. _, err := req.Execute(unix.NETLINK_ROUTE, 0)
  114. return err
  115. }
  116. // AddrList gets a list of IP addresses in the system.
  117. // Equivalent to: `ip addr show`.
  118. // The list can be filtered by link and ip family.
  119. func AddrList(link Link, family int) ([]Addr, error) {
  120. return pkgHandle.AddrList(link, family)
  121. }
  122. // AddrList gets a list of IP addresses in the system.
  123. // Equivalent to: `ip addr show`.
  124. // The list can be filtered by link and ip family.
  125. func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
  126. req := h.newNetlinkRequest(unix.RTM_GETADDR, unix.NLM_F_DUMP)
  127. msg := nl.NewIfInfomsg(family)
  128. req.AddData(msg)
  129. msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWADDR)
  130. if err != nil {
  131. return nil, err
  132. }
  133. indexFilter := 0
  134. if link != nil {
  135. base := link.Attrs()
  136. h.ensureIndex(base)
  137. indexFilter = base.Index
  138. }
  139. var res []Addr
  140. for _, m := range msgs {
  141. addr, msgFamily, ifindex, err := parseAddr(m)
  142. if err != nil {
  143. return res, err
  144. }
  145. if link != nil && ifindex != indexFilter {
  146. // Ignore messages from other interfaces
  147. continue
  148. }
  149. if family != FAMILY_ALL && msgFamily != family {
  150. continue
  151. }
  152. res = append(res, addr)
  153. }
  154. return res, nil
  155. }
  156. func parseAddr(m []byte) (addr Addr, family, index int, err error) {
  157. msg := nl.DeserializeIfAddrmsg(m)
  158. family = -1
  159. index = -1
  160. attrs, err1 := nl.ParseRouteAttr(m[msg.Len():])
  161. if err1 != nil {
  162. err = err1
  163. return
  164. }
  165. family = int(msg.Family)
  166. index = int(msg.Index)
  167. var local, dst *net.IPNet
  168. for _, attr := range attrs {
  169. switch attr.Attr.Type {
  170. case unix.IFA_ADDRESS:
  171. dst = &net.IPNet{
  172. IP: attr.Value,
  173. Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
  174. }
  175. addr.Peer = dst
  176. case unix.IFA_LOCAL:
  177. local = &net.IPNet{
  178. IP: attr.Value,
  179. Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
  180. }
  181. addr.IPNet = local
  182. case unix.IFA_BROADCAST:
  183. addr.Broadcast = attr.Value
  184. case unix.IFA_LABEL:
  185. addr.Label = string(attr.Value[:len(attr.Value)-1])
  186. case IFA_FLAGS:
  187. addr.Flags = int(native.Uint32(attr.Value[0:4]))
  188. case nl.IFA_CACHEINFO:
  189. ci := nl.DeserializeIfaCacheInfo(attr.Value)
  190. addr.PreferedLft = int(ci.IfaPrefered)
  191. addr.ValidLft = int(ci.IfaValid)
  192. }
  193. }
  194. // IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS
  195. if local != nil {
  196. addr.IPNet = local
  197. } else {
  198. addr.IPNet = dst
  199. }
  200. addr.Scope = int(msg.Scope)
  201. return
  202. }
  203. type AddrUpdate struct {
  204. LinkAddress net.IPNet
  205. LinkIndex int
  206. Flags int
  207. Scope int
  208. PreferedLft int
  209. ValidLft int
  210. NewAddr bool // true=added false=deleted
  211. }
  212. // AddrSubscribe takes a chan down which notifications will be sent
  213. // when addresses change. Close the 'done' chan to stop subscription.
  214. func AddrSubscribe(ch chan<- AddrUpdate, done <-chan struct{}) error {
  215. return addrSubscribeAt(netns.None(), netns.None(), ch, done, nil, false)
  216. }
  217. // AddrSubscribeAt works like AddrSubscribe plus it allows the caller
  218. // to choose the network namespace in which to subscribe (ns).
  219. func AddrSubscribeAt(ns netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error {
  220. return addrSubscribeAt(ns, netns.None(), ch, done, nil, false)
  221. }
  222. // AddrSubscribeOptions contains a set of options to use with
  223. // AddrSubscribeWithOptions.
  224. type AddrSubscribeOptions struct {
  225. Namespace *netns.NsHandle
  226. ErrorCallback func(error)
  227. ListExisting bool
  228. }
  229. // AddrSubscribeWithOptions work like AddrSubscribe but enable to
  230. // provide additional options to modify the behavior. Currently, the
  231. // namespace can be provided as well as an error callback.
  232. func AddrSubscribeWithOptions(ch chan<- AddrUpdate, done <-chan struct{}, options AddrSubscribeOptions) error {
  233. if options.Namespace == nil {
  234. none := netns.None()
  235. options.Namespace = &none
  236. }
  237. return addrSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting)
  238. }
  239. func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error {
  240. s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_IPV4_IFADDR, unix.RTNLGRP_IPV6_IFADDR)
  241. if err != nil {
  242. return err
  243. }
  244. if done != nil {
  245. go func() {
  246. <-done
  247. s.Close()
  248. }()
  249. }
  250. if listExisting {
  251. req := pkgHandle.newNetlinkRequest(unix.RTM_GETADDR,
  252. unix.NLM_F_DUMP)
  253. infmsg := nl.NewIfInfomsg(unix.AF_UNSPEC)
  254. req.AddData(infmsg)
  255. if err := s.Send(req); err != nil {
  256. return err
  257. }
  258. }
  259. go func() {
  260. defer close(ch)
  261. for {
  262. msgs, err := s.Receive()
  263. if err != nil {
  264. if cberr != nil {
  265. cberr(err)
  266. }
  267. return
  268. }
  269. for _, m := range msgs {
  270. if m.Header.Type == unix.NLMSG_DONE {
  271. continue
  272. }
  273. if m.Header.Type == unix.NLMSG_ERROR {
  274. native := nl.NativeEndian()
  275. error := int32(native.Uint32(m.Data[0:4]))
  276. if error == 0 {
  277. continue
  278. }
  279. if cberr != nil {
  280. cberr(syscall.Errno(-error))
  281. }
  282. return
  283. }
  284. msgType := m.Header.Type
  285. if msgType != unix.RTM_NEWADDR && msgType != unix.RTM_DELADDR {
  286. if cberr != nil {
  287. cberr(fmt.Errorf("bad message type: %d", msgType))
  288. }
  289. return
  290. }
  291. addr, _, ifindex, err := parseAddr(m.Data)
  292. if err != nil {
  293. if cberr != nil {
  294. cberr(fmt.Errorf("could not parse address: %v", err))
  295. }
  296. return
  297. }
  298. ch <- AddrUpdate{LinkAddress: *addr.IPNet,
  299. LinkIndex: ifindex,
  300. NewAddr: msgType == unix.RTM_NEWADDR,
  301. Flags: addr.Flags,
  302. Scope: addr.Scope,
  303. PreferedLft: addr.PreferedLft,
  304. ValidLft: addr.ValidLft}
  305. }
  306. }
  307. }()
  308. return nil
  309. }