addr_linux.go 6.0 KB

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