addr_linux.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  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. // AddrDel will delete an IP address from a link device.
  25. // Equivalent to: `ip addr del $addr dev $link`
  26. func AddrDel(link Link, addr *Addr) error {
  27. return pkgHandle.AddrDel(link, addr)
  28. }
  29. // AddrDel will delete an IP address from a link device.
  30. // Equivalent to: `ip addr del $addr dev $link`
  31. func (h *Handle) AddrDel(link Link, addr *Addr) error {
  32. req := h.newNetlinkRequest(syscall.RTM_DELADDR, syscall.NLM_F_ACK)
  33. return h.addrHandle(link, addr, req)
  34. }
  35. func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error {
  36. base := link.Attrs()
  37. if addr.Label != "" && !strings.HasPrefix(addr.Label, base.Name) {
  38. return fmt.Errorf("label must begin with interface name")
  39. }
  40. h.ensureIndex(base)
  41. family := nl.GetIPFamily(addr.IP)
  42. msg := nl.NewIfAddrmsg(family)
  43. msg.Index = uint32(base.Index)
  44. msg.Scope = uint8(addr.Scope)
  45. prefixlen, _ := addr.Mask.Size()
  46. msg.Prefixlen = uint8(prefixlen)
  47. req.AddData(msg)
  48. var localAddrData []byte
  49. if family == FAMILY_V4 {
  50. localAddrData = addr.IP.To4()
  51. } else {
  52. localAddrData = addr.IP.To16()
  53. }
  54. localData := nl.NewRtAttr(syscall.IFA_LOCAL, localAddrData)
  55. req.AddData(localData)
  56. var peerAddrData []byte
  57. if addr.Peer != nil {
  58. if family == FAMILY_V4 {
  59. peerAddrData = addr.Peer.IP.To4()
  60. } else {
  61. peerAddrData = addr.Peer.IP.To16()
  62. }
  63. } else {
  64. peerAddrData = localAddrData
  65. }
  66. addressData := nl.NewRtAttr(syscall.IFA_ADDRESS, peerAddrData)
  67. req.AddData(addressData)
  68. if addr.Flags != 0 {
  69. if addr.Flags <= 0xff {
  70. msg.IfAddrmsg.Flags = uint8(addr.Flags)
  71. } else {
  72. b := make([]byte, 4)
  73. native.PutUint32(b, uint32(addr.Flags))
  74. flagsData := nl.NewRtAttr(IFA_FLAGS, b)
  75. req.AddData(flagsData)
  76. }
  77. }
  78. if addr.Broadcast != nil {
  79. req.AddData(nl.NewRtAttr(syscall.IFA_BROADCAST, addr.Broadcast))
  80. }
  81. if addr.Label != "" {
  82. labelData := nl.NewRtAttr(syscall.IFA_LABEL, nl.ZeroTerminated(addr.Label))
  83. req.AddData(labelData)
  84. }
  85. _, err := req.Execute(syscall.NETLINK_ROUTE, 0)
  86. return err
  87. }
  88. // AddrList gets a list of IP addresses in the system.
  89. // Equivalent to: `ip addr show`.
  90. // The list can be filtered by link and ip family.
  91. func AddrList(link Link, family int) ([]Addr, error) {
  92. return pkgHandle.AddrList(link, family)
  93. }
  94. // AddrList gets a list of IP addresses in the system.
  95. // Equivalent to: `ip addr show`.
  96. // The list can be filtered by link and ip family.
  97. func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
  98. req := h.newNetlinkRequest(syscall.RTM_GETADDR, syscall.NLM_F_DUMP)
  99. msg := nl.NewIfInfomsg(family)
  100. req.AddData(msg)
  101. msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWADDR)
  102. if err != nil {
  103. return nil, err
  104. }
  105. indexFilter := 0
  106. if link != nil {
  107. base := link.Attrs()
  108. h.ensureIndex(base)
  109. indexFilter = base.Index
  110. }
  111. var res []Addr
  112. for _, m := range msgs {
  113. addr, msgFamily, ifindex, err := parseAddr(m)
  114. if err != nil {
  115. return res, err
  116. }
  117. if link != nil && ifindex != indexFilter {
  118. // Ignore messages from other interfaces
  119. continue
  120. }
  121. if family != FAMILY_ALL && msgFamily != family {
  122. continue
  123. }
  124. res = append(res, addr)
  125. }
  126. return res, nil
  127. }
  128. func parseAddr(m []byte) (addr Addr, family, index int, err error) {
  129. msg := nl.DeserializeIfAddrmsg(m)
  130. family = -1
  131. index = -1
  132. attrs, err1 := nl.ParseRouteAttr(m[msg.Len():])
  133. if err1 != nil {
  134. err = err1
  135. return
  136. }
  137. family = int(msg.Family)
  138. index = int(msg.Index)
  139. var local, dst *net.IPNet
  140. for _, attr := range attrs {
  141. switch attr.Attr.Type {
  142. case syscall.IFA_ADDRESS:
  143. dst = &net.IPNet{
  144. IP: attr.Value,
  145. Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
  146. }
  147. addr.Peer = dst
  148. case syscall.IFA_LOCAL:
  149. local = &net.IPNet{
  150. IP: attr.Value,
  151. Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
  152. }
  153. addr.IPNet = local
  154. case syscall.IFA_LABEL:
  155. addr.Label = string(attr.Value[:len(attr.Value)-1])
  156. case IFA_FLAGS:
  157. addr.Flags = int(native.Uint32(attr.Value[0:4]))
  158. }
  159. }
  160. // IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS
  161. if local != nil {
  162. addr.IPNet = local
  163. } else {
  164. addr.IPNet = dst
  165. }
  166. addr.Scope = int(msg.Scope)
  167. return
  168. }
  169. type AddrUpdate struct {
  170. LinkAddress net.IPNet
  171. LinkIndex int
  172. NewAddr bool // true=added false=deleted
  173. }
  174. // AddrSubscribe takes a chan down which notifications will be sent
  175. // when addresses change. Close the 'done' chan to stop subscription.
  176. func AddrSubscribe(ch chan<- AddrUpdate, done <-chan struct{}) error {
  177. return addrSubscribe(netns.None(), netns.None(), ch, done)
  178. }
  179. // AddrSubscribeAt works like AddrSubscribe plus it allows the caller
  180. // to choose the network namespace in which to subscribe (ns).
  181. func AddrSubscribeAt(ns netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error {
  182. return addrSubscribe(ns, netns.None(), ch, done)
  183. }
  184. func addrSubscribe(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error {
  185. s, err := nl.SubscribeAt(newNs, curNs, syscall.NETLINK_ROUTE, syscall.RTNLGRP_IPV4_IFADDR, syscall.RTNLGRP_IPV6_IFADDR)
  186. if err != nil {
  187. return err
  188. }
  189. if done != nil {
  190. go func() {
  191. <-done
  192. s.Close()
  193. }()
  194. }
  195. go func() {
  196. defer close(ch)
  197. for {
  198. msgs, err := s.Receive()
  199. if err != nil {
  200. log.Printf("netlink.AddrSubscribe: Receive() error: %v", err)
  201. return
  202. }
  203. for _, m := range msgs {
  204. msgType := m.Header.Type
  205. if msgType != syscall.RTM_NEWADDR && msgType != syscall.RTM_DELADDR {
  206. log.Printf("netlink.AddrSubscribe: bad message type: %d", msgType)
  207. continue
  208. }
  209. addr, _, ifindex, err := parseAddr(m.Data)
  210. if err != nil {
  211. log.Printf("netlink.AddrSubscribe: could not parse address: %v", err)
  212. continue
  213. }
  214. ch <- AddrUpdate{LinkAddress: *addr.IPNet, LinkIndex: ifindex, NewAddr: msgType == syscall.RTM_NEWADDR}
  215. }
  216. }
  217. }()
  218. return nil
  219. }