addr_linux.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  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. )
  10. // IFA_FLAGS is a u32 attribute.
  11. const IFA_FLAGS = 0x8
  12. // AddrAdd will add an IP address to a link device.
  13. // Equivalent to: `ip addr add $addr dev $link`
  14. func AddrAdd(link Link, addr *Addr) error {
  15. return pkgHandle.AddrAdd(link, addr)
  16. }
  17. // AddrAdd will add an IP address to a link device.
  18. // Equivalent to: `ip addr add $addr dev $link`
  19. func (h *Handle) AddrAdd(link Link, addr *Addr) error {
  20. req := h.newNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
  21. return h.addrHandle(link, addr, req)
  22. }
  23. // AddrReplace will replace (or, if not present, add) an IP address on a link device.
  24. // Equivalent to: `ip addr replace $addr dev $link`
  25. func AddrReplace(link Link, addr *Addr) error {
  26. return pkgHandle.AddrReplace(link, addr)
  27. }
  28. // AddrReplace will replace (or, if not present, add) an IP address on a link device.
  29. // Equivalent to: `ip addr replace $addr dev $link`
  30. func (h *Handle) AddrReplace(link Link, addr *Addr) error {
  31. req := h.newNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_REPLACE|syscall.NLM_F_ACK)
  32. return h.addrHandle(link, addr, req)
  33. }
  34. // AddrDel will delete an IP address from a link device.
  35. // Equivalent to: `ip addr del $addr dev $link`
  36. func AddrDel(link Link, addr *Addr) error {
  37. return pkgHandle.AddrDel(link, addr)
  38. }
  39. // AddrDel will delete an IP address from a link device.
  40. // Equivalent to: `ip addr del $addr dev $link`
  41. func (h *Handle) AddrDel(link Link, addr *Addr) error {
  42. req := h.newNetlinkRequest(syscall.RTM_DELADDR, syscall.NLM_F_ACK)
  43. return h.addrHandle(link, addr, req)
  44. }
  45. func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error {
  46. base := link.Attrs()
  47. if addr.Label != "" && !strings.HasPrefix(addr.Label, base.Name) {
  48. return fmt.Errorf("label must begin with interface name")
  49. }
  50. h.ensureIndex(base)
  51. family := nl.GetIPFamily(addr.IP)
  52. msg := nl.NewIfAddrmsg(family)
  53. msg.Index = uint32(base.Index)
  54. msg.Scope = uint8(addr.Scope)
  55. prefixlen, masklen := addr.Mask.Size()
  56. msg.Prefixlen = uint8(prefixlen)
  57. req.AddData(msg)
  58. var localAddrData []byte
  59. if family == FAMILY_V4 {
  60. localAddrData = addr.IP.To4()
  61. } else {
  62. localAddrData = addr.IP.To16()
  63. }
  64. localData := nl.NewRtAttr(syscall.IFA_LOCAL, localAddrData)
  65. req.AddData(localData)
  66. var peerAddrData []byte
  67. if addr.Peer != nil {
  68. if family == FAMILY_V4 {
  69. peerAddrData = addr.Peer.IP.To4()
  70. } else {
  71. peerAddrData = addr.Peer.IP.To16()
  72. }
  73. } else {
  74. peerAddrData = localAddrData
  75. }
  76. addressData := nl.NewRtAttr(syscall.IFA_ADDRESS, peerAddrData)
  77. req.AddData(addressData)
  78. if addr.Flags != 0 {
  79. if addr.Flags <= 0xff {
  80. msg.IfAddrmsg.Flags = uint8(addr.Flags)
  81. } else {
  82. b := make([]byte, 4)
  83. native.PutUint32(b, uint32(addr.Flags))
  84. flagsData := nl.NewRtAttr(IFA_FLAGS, b)
  85. req.AddData(flagsData)
  86. }
  87. }
  88. if addr.Broadcast == nil {
  89. calcBroadcast := make(net.IP, masklen/8)
  90. for i := range localAddrData {
  91. calcBroadcast[i] = localAddrData[i] | ^addr.Mask[i]
  92. }
  93. addr.Broadcast = calcBroadcast
  94. }
  95. req.AddData(nl.NewRtAttr(syscall.IFA_BROADCAST, addr.Broadcast))
  96. if addr.Label != "" {
  97. labelData := nl.NewRtAttr(syscall.IFA_LABEL, nl.ZeroTerminated(addr.Label))
  98. req.AddData(labelData)
  99. }
  100. _, err := req.Execute(syscall.NETLINK_ROUTE, 0)
  101. return err
  102. }
  103. // AddrList gets a list of IP addresses in the system.
  104. // Equivalent to: `ip addr show`.
  105. // The list can be filtered by link and ip family.
  106. func AddrList(link Link, family int) ([]Addr, error) {
  107. return pkgHandle.AddrList(link, family)
  108. }
  109. // AddrList gets a list of IP addresses in the system.
  110. // Equivalent to: `ip addr show`.
  111. // The list can be filtered by link and ip family.
  112. func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
  113. req := h.newNetlinkRequest(syscall.RTM_GETADDR, syscall.NLM_F_DUMP)
  114. msg := nl.NewIfInfomsg(family)
  115. req.AddData(msg)
  116. msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWADDR)
  117. if err != nil {
  118. return nil, err
  119. }
  120. indexFilter := 0
  121. if link != nil {
  122. base := link.Attrs()
  123. h.ensureIndex(base)
  124. indexFilter = base.Index
  125. }
  126. var res []Addr
  127. for _, m := range msgs {
  128. addr, msgFamily, ifindex, err := parseAddr(m)
  129. if err != nil {
  130. return res, err
  131. }
  132. if link != nil && ifindex != indexFilter {
  133. // Ignore messages from other interfaces
  134. continue
  135. }
  136. if family != FAMILY_ALL && msgFamily != family {
  137. continue
  138. }
  139. res = append(res, addr)
  140. }
  141. return res, nil
  142. }
  143. func parseAddr(m []byte) (addr Addr, family, index int, err error) {
  144. msg := nl.DeserializeIfAddrmsg(m)
  145. family = -1
  146. index = -1
  147. attrs, err1 := nl.ParseRouteAttr(m[msg.Len():])
  148. if err1 != nil {
  149. err = err1
  150. return
  151. }
  152. family = int(msg.Family)
  153. index = int(msg.Index)
  154. var local, dst *net.IPNet
  155. for _, attr := range attrs {
  156. switch attr.Attr.Type {
  157. case syscall.IFA_ADDRESS:
  158. dst = &net.IPNet{
  159. IP: attr.Value,
  160. Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
  161. }
  162. addr.Peer = dst
  163. case syscall.IFA_LOCAL:
  164. local = &net.IPNet{
  165. IP: attr.Value,
  166. Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
  167. }
  168. addr.IPNet = local
  169. case syscall.IFA_BROADCAST:
  170. addr.Broadcast = attr.Value
  171. case syscall.IFA_LABEL:
  172. addr.Label = string(attr.Value[:len(attr.Value)-1])
  173. case IFA_FLAGS:
  174. addr.Flags = int(native.Uint32(attr.Value[0:4]))
  175. case nl.IFA_CACHEINFO:
  176. ci := nl.DeserializeIfaCacheInfo(attr.Value)
  177. addr.PreferedLft = int(ci.IfaPrefered)
  178. addr.ValidLft = int(ci.IfaValid)
  179. }
  180. }
  181. // IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS
  182. if local != nil {
  183. addr.IPNet = local
  184. } else {
  185. addr.IPNet = dst
  186. }
  187. addr.Scope = int(msg.Scope)
  188. return
  189. }
  190. type AddrUpdate struct {
  191. LinkAddress net.IPNet
  192. LinkIndex int
  193. Flags int
  194. Scope int
  195. PreferedLft int
  196. ValidLft int
  197. NewAddr bool // true=added false=deleted
  198. }
  199. // AddrSubscribe takes a chan down which notifications will be sent
  200. // when addresses change. Close the 'done' chan to stop subscription.
  201. func AddrSubscribe(ch chan<- AddrUpdate, done <-chan struct{}) error {
  202. return addrSubscribeAt(netns.None(), netns.None(), ch, done, nil)
  203. }
  204. // AddrSubscribeAt works like AddrSubscribe plus it allows the caller
  205. // to choose the network namespace in which to subscribe (ns).
  206. func AddrSubscribeAt(ns netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error {
  207. return addrSubscribeAt(ns, netns.None(), ch, done, nil)
  208. }
  209. // AddrSubscribeOptions contains a set of options to use with
  210. // AddrSubscribeWithOptions.
  211. type AddrSubscribeOptions struct {
  212. Namespace *netns.NsHandle
  213. ErrorCallback func(error)
  214. }
  215. // AddrSubscribeWithOptions work like AddrSubscribe but enable to
  216. // provide additional options to modify the behavior. Currently, the
  217. // namespace can be provided as well as an error callback.
  218. func AddrSubscribeWithOptions(ch chan<- AddrUpdate, done <-chan struct{}, options AddrSubscribeOptions) error {
  219. if options.Namespace == nil {
  220. none := netns.None()
  221. options.Namespace = &none
  222. }
  223. return addrSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback)
  224. }
  225. func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error)) error {
  226. s, err := nl.SubscribeAt(newNs, curNs, syscall.NETLINK_ROUTE, syscall.RTNLGRP_IPV4_IFADDR, syscall.RTNLGRP_IPV6_IFADDR)
  227. if err != nil {
  228. return err
  229. }
  230. if done != nil {
  231. go func() {
  232. <-done
  233. s.Close()
  234. }()
  235. }
  236. go func() {
  237. defer close(ch)
  238. for {
  239. msgs, err := s.Receive()
  240. if err != nil {
  241. if cberr != nil {
  242. cberr(err)
  243. }
  244. return
  245. }
  246. for _, m := range msgs {
  247. msgType := m.Header.Type
  248. if msgType != syscall.RTM_NEWADDR && msgType != syscall.RTM_DELADDR {
  249. if cberr != nil {
  250. cberr(fmt.Errorf("bad message type: %d", msgType))
  251. }
  252. return
  253. }
  254. addr, _, ifindex, err := parseAddr(m.Data)
  255. if err != nil {
  256. if cberr != nil {
  257. cberr(fmt.Errorf("could not parse address: %v", err))
  258. }
  259. return
  260. }
  261. ch <- AddrUpdate{LinkAddress: *addr.IPNet,
  262. LinkIndex: ifindex,
  263. NewAddr: msgType == syscall.RTM_NEWADDR,
  264. Flags: addr.Flags,
  265. Scope: addr.Scope,
  266. PreferedLft: addr.PreferedLft,
  267. ValidLft: addr.ValidLft}
  268. }
  269. }
  270. }()
  271. return nil
  272. }