neigh_linux.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. package netlink
  2. import (
  3. "net"
  4. "unsafe"
  5. "github.com/vishvananda/netlink/nl"
  6. "golang.org/x/sys/unix"
  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, unix.NLM_F_CREATE|unix.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, unix.NLM_F_CREATE|unix.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, unix.NLM_F_CREATE|unix.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(unix.RTM_NEWNEIGH, mode|unix.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(unix.RTM_DELNEIGH, unix.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. if neigh.Vlan != 0 {
  138. vlanData := nl.NewRtAttr(NDA_VLAN, nl.Uint16Attr(uint16(neigh.Vlan)))
  139. req.AddData(vlanData)
  140. }
  141. if neigh.VNI != 0 {
  142. vniData := nl.NewRtAttr(NDA_VNI, nl.Uint32Attr(uint32(neigh.VNI)))
  143. req.AddData(vniData)
  144. }
  145. _, err := req.Execute(unix.NETLINK_ROUTE, 0)
  146. return err
  147. }
  148. // NeighList gets a list of IP-MAC mappings in the system (ARP table).
  149. // Equivalent to: `ip neighbor show`.
  150. // The list can be filtered by link and ip family.
  151. func NeighList(linkIndex, family int) ([]Neigh, error) {
  152. return pkgHandle.NeighList(linkIndex, family)
  153. }
  154. // NeighProxyList gets a list of neighbor proxies in the system.
  155. // Equivalent to: `ip neighbor show proxy`.
  156. // The list can be filtered by link and ip family.
  157. func NeighProxyList(linkIndex, family int) ([]Neigh, error) {
  158. return pkgHandle.NeighProxyList(linkIndex, family)
  159. }
  160. // NeighList gets a list of IP-MAC mappings in the system (ARP table).
  161. // Equivalent to: `ip neighbor show`.
  162. // The list can be filtered by link and ip family.
  163. func (h *Handle) NeighList(linkIndex, family int) ([]Neigh, error) {
  164. return h.neighList(linkIndex, family, 0)
  165. }
  166. // NeighProxyList gets a list of neighbor proxies in the system.
  167. // Equivalent to: `ip neighbor show proxy`.
  168. // The list can be filtered by link, ip family.
  169. func (h *Handle) NeighProxyList(linkIndex, family int) ([]Neigh, error) {
  170. return h.neighList(linkIndex, family, NTF_PROXY)
  171. }
  172. func (h *Handle) neighList(linkIndex, family, flags int) ([]Neigh, error) {
  173. req := h.newNetlinkRequest(unix.RTM_GETNEIGH, unix.NLM_F_DUMP)
  174. msg := Ndmsg{
  175. Family: uint8(family),
  176. Index: uint32(linkIndex),
  177. Flags: uint8(flags),
  178. }
  179. req.AddData(&msg)
  180. msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNEIGH)
  181. if err != nil {
  182. return nil, err
  183. }
  184. var res []Neigh
  185. for _, m := range msgs {
  186. ndm := deserializeNdmsg(m)
  187. if linkIndex != 0 && int(ndm.Index) != linkIndex {
  188. // Ignore messages from other interfaces
  189. continue
  190. }
  191. neigh, err := NeighDeserialize(m)
  192. if err != nil {
  193. continue
  194. }
  195. res = append(res, *neigh)
  196. }
  197. return res, nil
  198. }
  199. func NeighDeserialize(m []byte) (*Neigh, error) {
  200. msg := deserializeNdmsg(m)
  201. neigh := Neigh{
  202. LinkIndex: int(msg.Index),
  203. Family: int(msg.Family),
  204. State: int(msg.State),
  205. Type: int(msg.Type),
  206. Flags: int(msg.Flags),
  207. }
  208. attrs, err := nl.ParseRouteAttr(m[msg.Len():])
  209. if err != nil {
  210. return nil, err
  211. }
  212. // This should be cached for perfomance
  213. // once per table dump
  214. link, err := LinkByIndex(neigh.LinkIndex)
  215. if err != nil {
  216. return nil, err
  217. }
  218. encapType := link.Attrs().EncapType
  219. for _, attr := range attrs {
  220. switch attr.Attr.Type {
  221. case NDA_DST:
  222. neigh.IP = net.IP(attr.Value)
  223. case NDA_LLADDR:
  224. // BUG: Is this a bug in the netlink library?
  225. // #define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
  226. // #define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))
  227. attrLen := attr.Attr.Len - unix.SizeofRtAttr
  228. if attrLen == 4 && (encapType == "ipip" ||
  229. encapType == "sit" ||
  230. encapType == "gre") {
  231. neigh.LLIPAddr = net.IP(attr.Value)
  232. } else if attrLen == 16 &&
  233. encapType == "tunnel6" {
  234. neigh.IP = net.IP(attr.Value)
  235. } else {
  236. neigh.HardwareAddr = net.HardwareAddr(attr.Value)
  237. }
  238. case NDA_VLAN:
  239. neigh.Vlan = int(native.Uint16(attr.Value[0:2]))
  240. case NDA_VNI:
  241. neigh.VNI = int(native.Uint32(attr.Value[0:4]))
  242. }
  243. }
  244. return &neigh, nil
  245. }