neigh_linux.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. package netlink
  2. import (
  3. "net"
  4. "syscall"
  5. "unsafe"
  6. "github.com/vishvananda/netlink/nl"
  7. )
  8. const (
  9. NDA_UNSPEC = iota
  10. NDA_DST
  11. NDA_LLADDR
  12. NDA_CACHEINFO
  13. NDA_PROBES
  14. NDA_VLAN
  15. NDA_PORT
  16. NDA_VNI
  17. NDA_IFINDEX
  18. NDA_MAX = NDA_IFINDEX
  19. )
  20. // Neighbor Cache Entry States.
  21. const (
  22. NUD_NONE = 0x00
  23. NUD_INCOMPLETE = 0x01
  24. NUD_REACHABLE = 0x02
  25. NUD_STALE = 0x04
  26. NUD_DELAY = 0x08
  27. NUD_PROBE = 0x10
  28. NUD_FAILED = 0x20
  29. NUD_NOARP = 0x40
  30. NUD_PERMANENT = 0x80
  31. )
  32. // Neighbor Flags
  33. const (
  34. NTF_USE = 0x01
  35. NTF_SELF = 0x02
  36. NTF_MASTER = 0x04
  37. NTF_PROXY = 0x08
  38. NTF_ROUTER = 0x80
  39. )
  40. type Ndmsg struct {
  41. Family uint8
  42. Index uint32
  43. State uint16
  44. Flags uint8
  45. Type uint8
  46. }
  47. func deserializeNdmsg(b []byte) *Ndmsg {
  48. var dummy Ndmsg
  49. return (*Ndmsg)(unsafe.Pointer(&b[0:unsafe.Sizeof(dummy)][0]))
  50. }
  51. func (msg *Ndmsg) Serialize() []byte {
  52. return (*(*[unsafe.Sizeof(*msg)]byte)(unsafe.Pointer(msg)))[:]
  53. }
  54. func (msg *Ndmsg) Len() int {
  55. return int(unsafe.Sizeof(*msg))
  56. }
  57. // NeighAdd will add an IP to MAC mapping to the ARP table
  58. // Equivalent to: `ip neigh add ....`
  59. func NeighAdd(neigh *Neigh) error {
  60. return pkgHandle.NeighAdd(neigh)
  61. }
  62. // NeighAdd will add an IP to MAC mapping to the ARP table
  63. // Equivalent to: `ip neigh add ....`
  64. func (h *Handle) NeighAdd(neigh *Neigh) error {
  65. return h.neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL)
  66. }
  67. // NeighSet will add or replace an IP to MAC mapping to the ARP table
  68. // Equivalent to: `ip neigh replace....`
  69. func NeighSet(neigh *Neigh) error {
  70. return pkgHandle.NeighSet(neigh)
  71. }
  72. // NeighSet will add or replace an IP to MAC mapping to the ARP table
  73. // Equivalent to: `ip neigh replace....`
  74. func (h *Handle) NeighSet(neigh *Neigh) error {
  75. return h.neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_REPLACE)
  76. }
  77. // NeighAppend will append an entry to FDB
  78. // Equivalent to: `bridge fdb append...`
  79. func NeighAppend(neigh *Neigh) error {
  80. return pkgHandle.NeighAppend(neigh)
  81. }
  82. // NeighAppend will append an entry to FDB
  83. // Equivalent to: `bridge fdb append...`
  84. func (h *Handle) NeighAppend(neigh *Neigh) error {
  85. return h.neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_APPEND)
  86. }
  87. // NeighAppend will append an entry to FDB
  88. // Equivalent to: `bridge fdb append...`
  89. func neighAdd(neigh *Neigh, mode int) error {
  90. return pkgHandle.neighAdd(neigh, mode)
  91. }
  92. // NeighAppend will append an entry to FDB
  93. // Equivalent to: `bridge fdb append...`
  94. func (h *Handle) neighAdd(neigh *Neigh, mode int) error {
  95. req := h.newNetlinkRequest(syscall.RTM_NEWNEIGH, mode|syscall.NLM_F_ACK)
  96. return neighHandle(neigh, req)
  97. }
  98. // NeighDel will delete an IP address from a link device.
  99. // Equivalent to: `ip addr del $addr dev $link`
  100. func NeighDel(neigh *Neigh) error {
  101. return pkgHandle.NeighDel(neigh)
  102. }
  103. // NeighDel will delete an IP address from a link device.
  104. // Equivalent to: `ip addr del $addr dev $link`
  105. func (h *Handle) NeighDel(neigh *Neigh) error {
  106. req := h.newNetlinkRequest(syscall.RTM_DELNEIGH, syscall.NLM_F_ACK)
  107. return neighHandle(neigh, req)
  108. }
  109. func neighHandle(neigh *Neigh, req *nl.NetlinkRequest) error {
  110. var family int
  111. if neigh.Family > 0 {
  112. family = neigh.Family
  113. } else {
  114. family = nl.GetIPFamily(neigh.IP)
  115. }
  116. msg := Ndmsg{
  117. Family: uint8(family),
  118. Index: uint32(neigh.LinkIndex),
  119. State: uint16(neigh.State),
  120. Type: uint8(neigh.Type),
  121. Flags: uint8(neigh.Flags),
  122. }
  123. req.AddData(&msg)
  124. ipData := neigh.IP.To4()
  125. if ipData == nil {
  126. ipData = neigh.IP.To16()
  127. }
  128. dstData := nl.NewRtAttr(NDA_DST, ipData)
  129. req.AddData(dstData)
  130. if neigh.LLIPAddr != nil {
  131. llIPData := nl.NewRtAttr(NDA_LLADDR, neigh.LLIPAddr.To4())
  132. req.AddData(llIPData)
  133. } else if neigh.Flags != NTF_PROXY || neigh.HardwareAddr != nil {
  134. hwData := nl.NewRtAttr(NDA_LLADDR, []byte(neigh.HardwareAddr))
  135. req.AddData(hwData)
  136. }
  137. _, err := req.Execute(syscall.NETLINK_ROUTE, 0)
  138. return err
  139. }
  140. // NeighList gets a list of IP-MAC mappings in the system (ARP table).
  141. // Equivalent to: `ip neighbor show`.
  142. // The list can be filtered by link and ip family.
  143. func NeighList(linkIndex, family int) ([]Neigh, error) {
  144. return pkgHandle.NeighList(linkIndex, family)
  145. }
  146. // NeighProxyList gets a list of neighbor proxies in the system.
  147. // Equivalent to: `ip neighbor show proxy`.
  148. // The list can be filtered by link and ip family.
  149. func NeighProxyList(linkIndex, family int) ([]Neigh, error) {
  150. return pkgHandle.NeighProxyList(linkIndex, family)
  151. }
  152. // NeighList gets a list of IP-MAC mappings in the system (ARP table).
  153. // Equivalent to: `ip neighbor show`.
  154. // The list can be filtered by link and ip family.
  155. func (h *Handle) NeighList(linkIndex, family int) ([]Neigh, error) {
  156. return h.neighList(linkIndex, family, 0)
  157. }
  158. // NeighProxyList gets a list of neighbor proxies in the system.
  159. // Equivalent to: `ip neighbor show proxy`.
  160. // The list can be filtered by link, ip family.
  161. func (h *Handle) NeighProxyList(linkIndex, family int) ([]Neigh, error) {
  162. return h.neighList(linkIndex, family, NTF_PROXY)
  163. }
  164. func (h *Handle) neighList(linkIndex, family, flags int) ([]Neigh, error) {
  165. req := h.newNetlinkRequest(syscall.RTM_GETNEIGH, syscall.NLM_F_DUMP)
  166. msg := Ndmsg{
  167. Family: uint8(family),
  168. Index: uint32(linkIndex),
  169. Flags: uint8(flags),
  170. }
  171. req.AddData(&msg)
  172. msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWNEIGH)
  173. if err != nil {
  174. return nil, err
  175. }
  176. var res []Neigh
  177. for _, m := range msgs {
  178. ndm := deserializeNdmsg(m)
  179. if linkIndex != 0 && int(ndm.Index) != linkIndex {
  180. // Ignore messages from other interfaces
  181. continue
  182. }
  183. neigh, err := NeighDeserialize(m)
  184. if err != nil {
  185. continue
  186. }
  187. res = append(res, *neigh)
  188. }
  189. return res, nil
  190. }
  191. func NeighDeserialize(m []byte) (*Neigh, error) {
  192. msg := deserializeNdmsg(m)
  193. neigh := Neigh{
  194. LinkIndex: int(msg.Index),
  195. Family: int(msg.Family),
  196. State: int(msg.State),
  197. Type: int(msg.Type),
  198. Flags: int(msg.Flags),
  199. }
  200. attrs, err := nl.ParseRouteAttr(m[msg.Len():])
  201. if err != nil {
  202. return nil, err
  203. }
  204. // This should be cached for perfomance
  205. // once per table dump
  206. link, err := LinkByIndex(neigh.LinkIndex)
  207. if err != nil {
  208. return nil, err
  209. }
  210. encapType := link.Attrs().EncapType
  211. for _, attr := range attrs {
  212. switch attr.Attr.Type {
  213. case NDA_DST:
  214. neigh.IP = net.IP(attr.Value)
  215. case NDA_LLADDR:
  216. // BUG: Is this a bug in the netlink library?
  217. // #define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
  218. // #define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))
  219. attrLen := attr.Attr.Len - syscall.SizeofRtAttr
  220. if attrLen == 4 && (encapType == "ipip" ||
  221. encapType == "sit" ||
  222. encapType == "gre") {
  223. neigh.LLIPAddr = net.IP(attr.Value)
  224. } else if attrLen == 16 &&
  225. encapType == "tunnel6" {
  226. neigh.IP = net.IP(attr.Value)
  227. } else {
  228. neigh.HardwareAddr = net.HardwareAddr(attr.Value)
  229. }
  230. }
  231. }
  232. return &neigh, nil
  233. }