addr_linux.go 5.5 KB

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