addr_linux.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. package netlink
  2. import (
  3. "fmt"
  4. "log"
  5. "net"
  6. "strings"
  7. "syscall"
  8. "github.com/vishvananda/netlink/nl"
  9. "github.com/vishvananda/netns"
  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(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.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(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_REPLACE|syscall.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(syscall.RTM_DELADDR, syscall.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, _ := 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(syscall.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(syscall.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 addr.Broadcast != nil {
  90. req.AddData(nl.NewRtAttr(syscall.IFA_BROADCAST, addr.Broadcast))
  91. }
  92. if addr.Label != "" {
  93. labelData := nl.NewRtAttr(syscall.IFA_LABEL, nl.ZeroTerminated(addr.Label))
  94. req.AddData(labelData)
  95. }
  96. _, err := req.Execute(syscall.NETLINK_ROUTE, 0)
  97. return err
  98. }
  99. // AddrList gets a list of IP addresses in the system.
  100. // Equivalent to: `ip addr show`.
  101. // The list can be filtered by link and ip family.
  102. func AddrList(link Link, family int) ([]Addr, error) {
  103. return pkgHandle.AddrList(link, family)
  104. }
  105. // AddrList gets a list of IP addresses in the system.
  106. // Equivalent to: `ip addr show`.
  107. // The list can be filtered by link and ip family.
  108. func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
  109. req := h.newNetlinkRequest(syscall.RTM_GETADDR, syscall.NLM_F_DUMP)
  110. msg := nl.NewIfInfomsg(family)
  111. req.AddData(msg)
  112. msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWADDR)
  113. if err != nil {
  114. return nil, err
  115. }
  116. indexFilter := 0
  117. if link != nil {
  118. base := link.Attrs()
  119. h.ensureIndex(base)
  120. indexFilter = base.Index
  121. }
  122. var res []Addr
  123. for _, m := range msgs {
  124. addr, msgFamily, ifindex, err := parseAddr(m)
  125. if err != nil {
  126. return res, err
  127. }
  128. if link != nil && ifindex != indexFilter {
  129. // Ignore messages from other interfaces
  130. continue
  131. }
  132. if family != FAMILY_ALL && msgFamily != family {
  133. continue
  134. }
  135. res = append(res, addr)
  136. }
  137. return res, nil
  138. }
  139. func parseAddr(m []byte) (addr Addr, family, index int, err error) {
  140. msg := nl.DeserializeIfAddrmsg(m)
  141. family = -1
  142. index = -1
  143. attrs, err1 := nl.ParseRouteAttr(m[msg.Len():])
  144. if err1 != nil {
  145. err = err1
  146. return
  147. }
  148. family = int(msg.Family)
  149. index = int(msg.Index)
  150. var local, dst *net.IPNet
  151. for _, attr := range attrs {
  152. switch attr.Attr.Type {
  153. case syscall.IFA_ADDRESS:
  154. dst = &net.IPNet{
  155. IP: attr.Value,
  156. Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
  157. }
  158. addr.Peer = dst
  159. case syscall.IFA_LOCAL:
  160. local = &net.IPNet{
  161. IP: attr.Value,
  162. Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
  163. }
  164. addr.IPNet = local
  165. case syscall.IFA_LABEL:
  166. addr.Label = string(attr.Value[:len(attr.Value)-1])
  167. case IFA_FLAGS:
  168. addr.Flags = int(native.Uint32(attr.Value[0:4]))
  169. }
  170. }
  171. // IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS
  172. if local != nil {
  173. addr.IPNet = local
  174. } else {
  175. addr.IPNet = dst
  176. }
  177. addr.Scope = int(msg.Scope)
  178. return
  179. }
  180. type AddrUpdate struct {
  181. LinkAddress net.IPNet
  182. LinkIndex int
  183. NewAddr bool // true=added false=deleted
  184. }
  185. // AddrSubscribe takes a chan down which notifications will be sent
  186. // when addresses change. Close the 'done' chan to stop subscription.
  187. func AddrSubscribe(ch chan<- AddrUpdate, done <-chan struct{}) error {
  188. return addrSubscribe(netns.None(), netns.None(), ch, done)
  189. }
  190. // AddrSubscribeAt works like AddrSubscribe plus it allows the caller
  191. // to choose the network namespace in which to subscribe (ns).
  192. func AddrSubscribeAt(ns netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error {
  193. return addrSubscribe(ns, netns.None(), ch, done)
  194. }
  195. func addrSubscribe(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error {
  196. s, err := nl.SubscribeAt(newNs, curNs, syscall.NETLINK_ROUTE, syscall.RTNLGRP_IPV4_IFADDR, syscall.RTNLGRP_IPV6_IFADDR)
  197. if err != nil {
  198. return err
  199. }
  200. if done != nil {
  201. go func() {
  202. <-done
  203. s.Close()
  204. }()
  205. }
  206. go func() {
  207. defer close(ch)
  208. for {
  209. msgs, err := s.Receive()
  210. if err != nil {
  211. log.Printf("netlink.AddrSubscribe: Receive() error: %v", err)
  212. return
  213. }
  214. for _, m := range msgs {
  215. msgType := m.Header.Type
  216. if msgType != syscall.RTM_NEWADDR && msgType != syscall.RTM_DELADDR {
  217. log.Printf("netlink.AddrSubscribe: bad message type: %d", msgType)
  218. continue
  219. }
  220. addr, _, ifindex, err := parseAddr(m.Data)
  221. if err != nil {
  222. log.Printf("netlink.AddrSubscribe: could not parse address: %v", err)
  223. continue
  224. }
  225. ch <- AddrUpdate{LinkAddress: *addr.IPNet, LinkIndex: ifindex, NewAddr: msgType == syscall.RTM_NEWADDR}
  226. }
  227. }
  228. }()
  229. return nil
  230. }