neigh_linux.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  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 neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL)
  61. }
  62. // NeighSet will add or replace an IP to MAC mapping to the ARP table
  63. // Equivalent to: `ip neigh replace....`
  64. func NeighSet(neigh *Neigh) error {
  65. return neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_REPLACE)
  66. }
  67. // NeighAppend will append an entry to FDB
  68. // Equivalent to: `bridge fdb append...`
  69. func NeighAppend(neigh *Neigh) error {
  70. return neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_APPEND)
  71. }
  72. func neighAdd(neigh *Neigh, mode int) error {
  73. req := nl.NewNetlinkRequest(syscall.RTM_NEWNEIGH, mode|syscall.NLM_F_ACK)
  74. return neighHandle(neigh, req)
  75. }
  76. // NeighDel will delete an IP address from a link device.
  77. // Equivalent to: `ip addr del $addr dev $link`
  78. func NeighDel(neigh *Neigh) error {
  79. req := nl.NewNetlinkRequest(syscall.RTM_DELNEIGH, syscall.NLM_F_ACK)
  80. return neighHandle(neigh, req)
  81. }
  82. func neighHandle(neigh *Neigh, req *nl.NetlinkRequest) error {
  83. var family int
  84. if neigh.Family > 0 {
  85. family = neigh.Family
  86. } else {
  87. family = nl.GetIPFamily(neigh.IP)
  88. }
  89. msg := Ndmsg{
  90. Family: uint8(family),
  91. Index: uint32(neigh.LinkIndex),
  92. State: uint16(neigh.State),
  93. Type: uint8(neigh.Type),
  94. Flags: uint8(neigh.Flags),
  95. }
  96. req.AddData(&msg)
  97. ipData := neigh.IP.To4()
  98. if ipData == nil {
  99. ipData = neigh.IP.To16()
  100. }
  101. dstData := nl.NewRtAttr(NDA_DST, ipData)
  102. req.AddData(dstData)
  103. hwData := nl.NewRtAttr(NDA_LLADDR, []byte(neigh.HardwareAddr))
  104. req.AddData(hwData)
  105. _, err := req.Execute(syscall.NETLINK_ROUTE, 0)
  106. return err
  107. }
  108. // NeighList gets a list of IP-MAC mappings in the system (ARP table).
  109. // Equivalent to: `ip neighbor show`.
  110. // The list can be filtered by link and ip family.
  111. func NeighList(linkIndex, family int) ([]Neigh, error) {
  112. req := nl.NewNetlinkRequest(syscall.RTM_GETNEIGH, syscall.NLM_F_DUMP)
  113. msg := Ndmsg{
  114. Family: uint8(family),
  115. Index: uint32(linkIndex),
  116. }
  117. req.AddData(&msg)
  118. msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWNEIGH)
  119. if err != nil {
  120. return nil, err
  121. }
  122. var res []Neigh
  123. for _, m := range msgs {
  124. ndm := deserializeNdmsg(m)
  125. if linkIndex != 0 && int(ndm.Index) != linkIndex {
  126. // Ignore messages from other interfaces
  127. continue
  128. }
  129. neigh, err := NeighDeserialize(m)
  130. if err != nil {
  131. continue
  132. }
  133. res = append(res, *neigh)
  134. }
  135. return res, nil
  136. }
  137. func NeighDeserialize(m []byte) (*Neigh, error) {
  138. msg := deserializeNdmsg(m)
  139. neigh := Neigh{
  140. LinkIndex: int(msg.Index),
  141. Family: int(msg.Family),
  142. State: int(msg.State),
  143. Type: int(msg.Type),
  144. Flags: int(msg.Flags),
  145. }
  146. attrs, err := nl.ParseRouteAttr(m[msg.Len():])
  147. if err != nil {
  148. return nil, err
  149. }
  150. for _, attr := range attrs {
  151. switch attr.Attr.Type {
  152. case NDA_DST:
  153. neigh.IP = net.IP(attr.Value)
  154. case NDA_LLADDR:
  155. neigh.HardwareAddr = net.HardwareAddr(attr.Value)
  156. }
  157. }
  158. return &neigh, nil
  159. }