neigh_linux.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. package netlink
  2. import (
  3. "fmt"
  4. "net"
  5. "syscall"
  6. "unsafe"
  7. "github.com/vishvananda/netlink/nl"
  8. "github.com/vishvananda/netns"
  9. "golang.org/x/sys/unix"
  10. )
  11. const (
  12. NDA_UNSPEC = iota
  13. NDA_DST
  14. NDA_LLADDR
  15. NDA_CACHEINFO
  16. NDA_PROBES
  17. NDA_VLAN
  18. NDA_PORT
  19. NDA_VNI
  20. NDA_IFINDEX
  21. NDA_MASTER
  22. NDA_LINK_NETNSID
  23. NDA_SRC_VNI
  24. NDA_MAX = NDA_SRC_VNI
  25. )
  26. // Neighbor Cache Entry States.
  27. const (
  28. NUD_NONE = 0x00
  29. NUD_INCOMPLETE = 0x01
  30. NUD_REACHABLE = 0x02
  31. NUD_STALE = 0x04
  32. NUD_DELAY = 0x08
  33. NUD_PROBE = 0x10
  34. NUD_FAILED = 0x20
  35. NUD_NOARP = 0x40
  36. NUD_PERMANENT = 0x80
  37. )
  38. // Neighbor Flags
  39. const (
  40. NTF_USE = 0x01
  41. NTF_SELF = 0x02
  42. NTF_MASTER = 0x04
  43. NTF_PROXY = 0x08
  44. NTF_ROUTER = 0x80
  45. )
  46. // Ndmsg is for adding, removing or receiving information about a neighbor table entry
  47. type Ndmsg struct {
  48. Family uint8
  49. Index uint32
  50. State uint16
  51. Flags uint8
  52. Type uint8
  53. }
  54. func deserializeNdmsg(b []byte) *Ndmsg {
  55. var dummy Ndmsg
  56. return (*Ndmsg)(unsafe.Pointer(&b[0:unsafe.Sizeof(dummy)][0]))
  57. }
  58. func (msg *Ndmsg) Serialize() []byte {
  59. return (*(*[unsafe.Sizeof(*msg)]byte)(unsafe.Pointer(msg)))[:]
  60. }
  61. func (msg *Ndmsg) Len() int {
  62. return int(unsafe.Sizeof(*msg))
  63. }
  64. // NeighAdd will add an IP to MAC mapping to the ARP table
  65. // Equivalent to: `ip neigh add ....`
  66. func NeighAdd(neigh *Neigh) error {
  67. return pkgHandle.NeighAdd(neigh)
  68. }
  69. // NeighAdd will add an IP to MAC mapping to the ARP table
  70. // Equivalent to: `ip neigh add ....`
  71. func (h *Handle) NeighAdd(neigh *Neigh) error {
  72. return h.neighAdd(neigh, unix.NLM_F_CREATE|unix.NLM_F_EXCL)
  73. }
  74. // NeighSet will add or replace an IP to MAC mapping to the ARP table
  75. // Equivalent to: `ip neigh replace....`
  76. func NeighSet(neigh *Neigh) error {
  77. return pkgHandle.NeighSet(neigh)
  78. }
  79. // NeighSet will add or replace an IP to MAC mapping to the ARP table
  80. // Equivalent to: `ip neigh replace....`
  81. func (h *Handle) NeighSet(neigh *Neigh) error {
  82. return h.neighAdd(neigh, unix.NLM_F_CREATE|unix.NLM_F_REPLACE)
  83. }
  84. // NeighAppend will append an entry to FDB
  85. // Equivalent to: `bridge fdb append...`
  86. func NeighAppend(neigh *Neigh) error {
  87. return pkgHandle.NeighAppend(neigh)
  88. }
  89. // NeighAppend will append an entry to FDB
  90. // Equivalent to: `bridge fdb append...`
  91. func (h *Handle) NeighAppend(neigh *Neigh) error {
  92. return h.neighAdd(neigh, unix.NLM_F_CREATE|unix.NLM_F_APPEND)
  93. }
  94. // NeighAppend will append an entry to FDB
  95. // Equivalent to: `bridge fdb append...`
  96. func neighAdd(neigh *Neigh, mode int) error {
  97. return pkgHandle.neighAdd(neigh, mode)
  98. }
  99. // NeighAppend will append an entry to FDB
  100. // Equivalent to: `bridge fdb append...`
  101. func (h *Handle) neighAdd(neigh *Neigh, mode int) error {
  102. req := h.newNetlinkRequest(unix.RTM_NEWNEIGH, mode|unix.NLM_F_ACK)
  103. return neighHandle(neigh, req)
  104. }
  105. // NeighDel will delete an IP address from a link device.
  106. // Equivalent to: `ip addr del $addr dev $link`
  107. func NeighDel(neigh *Neigh) error {
  108. return pkgHandle.NeighDel(neigh)
  109. }
  110. // NeighDel will delete an IP address from a link device.
  111. // Equivalent to: `ip addr del $addr dev $link`
  112. func (h *Handle) NeighDel(neigh *Neigh) error {
  113. req := h.newNetlinkRequest(unix.RTM_DELNEIGH, unix.NLM_F_ACK)
  114. return neighHandle(neigh, req)
  115. }
  116. func neighHandle(neigh *Neigh, req *nl.NetlinkRequest) error {
  117. var family int
  118. if neigh.Family > 0 {
  119. family = neigh.Family
  120. } else {
  121. family = nl.GetIPFamily(neigh.IP)
  122. }
  123. msg := Ndmsg{
  124. Family: uint8(family),
  125. Index: uint32(neigh.LinkIndex),
  126. State: uint16(neigh.State),
  127. Type: uint8(neigh.Type),
  128. Flags: uint8(neigh.Flags),
  129. }
  130. req.AddData(&msg)
  131. ipData := neigh.IP.To4()
  132. if ipData == nil {
  133. ipData = neigh.IP.To16()
  134. }
  135. dstData := nl.NewRtAttr(NDA_DST, ipData)
  136. req.AddData(dstData)
  137. if neigh.LLIPAddr != nil {
  138. llIPData := nl.NewRtAttr(NDA_LLADDR, neigh.LLIPAddr.To4())
  139. req.AddData(llIPData)
  140. } else if neigh.Flags != NTF_PROXY || neigh.HardwareAddr != nil {
  141. hwData := nl.NewRtAttr(NDA_LLADDR, []byte(neigh.HardwareAddr))
  142. req.AddData(hwData)
  143. }
  144. if neigh.Vlan != 0 {
  145. vlanData := nl.NewRtAttr(NDA_VLAN, nl.Uint16Attr(uint16(neigh.Vlan)))
  146. req.AddData(vlanData)
  147. }
  148. if neigh.VNI != 0 {
  149. vniData := nl.NewRtAttr(NDA_VNI, nl.Uint32Attr(uint32(neigh.VNI)))
  150. req.AddData(vniData)
  151. }
  152. if neigh.MasterIndex != 0 {
  153. masterData := nl.NewRtAttr(NDA_MASTER, nl.Uint32Attr(uint32(neigh.MasterIndex)))
  154. req.AddData(masterData)
  155. }
  156. _, err := req.Execute(unix.NETLINK_ROUTE, 0)
  157. return err
  158. }
  159. // NeighList returns a list of IP-MAC mappings in the system (ARP table).
  160. // Equivalent to: `ip neighbor show`.
  161. // The list can be filtered by link and ip family.
  162. func NeighList(linkIndex, family int) ([]Neigh, error) {
  163. return pkgHandle.NeighList(linkIndex, family)
  164. }
  165. // NeighProxyList returns a list of neighbor proxies in the system.
  166. // Equivalent to: `ip neighbor show proxy`.
  167. // The list can be filtered by link and ip family.
  168. func NeighProxyList(linkIndex, family int) ([]Neigh, error) {
  169. return pkgHandle.NeighProxyList(linkIndex, family)
  170. }
  171. // NeighList returns a list of IP-MAC mappings in the system (ARP table).
  172. // Equivalent to: `ip neighbor show`.
  173. // The list can be filtered by link and ip family.
  174. func (h *Handle) NeighList(linkIndex, family int) ([]Neigh, error) {
  175. return h.NeighListExecute(Ndmsg{
  176. Family: uint8(family),
  177. Index: uint32(linkIndex),
  178. })
  179. }
  180. // NeighProxyList returns a list of neighbor proxies in the system.
  181. // Equivalent to: `ip neighbor show proxy`.
  182. // The list can be filtered by link, ip family.
  183. func (h *Handle) NeighProxyList(linkIndex, family int) ([]Neigh, error) {
  184. return h.NeighListExecute(Ndmsg{
  185. Family: uint8(family),
  186. Index: uint32(linkIndex),
  187. Flags: NTF_PROXY,
  188. })
  189. }
  190. // NeighListExecute returns a list of neighbour entries filtered by link, ip family, flag and state.
  191. func NeighListExecute(msg Ndmsg) ([]Neigh, error) {
  192. return pkgHandle.NeighListExecute(msg)
  193. }
  194. // NeighListExecute returns a list of neighbour entries filtered by link, ip family, flag and state.
  195. func (h *Handle) NeighListExecute(msg Ndmsg) ([]Neigh, error) {
  196. req := h.newNetlinkRequest(unix.RTM_GETNEIGH, unix.NLM_F_DUMP)
  197. req.AddData(&msg)
  198. msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNEIGH)
  199. if err != nil {
  200. return nil, err
  201. }
  202. var res []Neigh
  203. for _, m := range msgs {
  204. ndm := deserializeNdmsg(m)
  205. if msg.Index != 0 && ndm.Index != msg.Index {
  206. // Ignore messages from other interfaces
  207. continue
  208. }
  209. if msg.Family != 0 && ndm.Family != msg.Family {
  210. continue
  211. }
  212. if msg.State != 0 && ndm.State != msg.State {
  213. continue
  214. }
  215. if msg.Type != 0 && ndm.Type != msg.Type {
  216. continue
  217. }
  218. if msg.Flags != 0 && ndm.Flags != msg.Flags {
  219. continue
  220. }
  221. neigh, err := NeighDeserialize(m)
  222. if err != nil {
  223. continue
  224. }
  225. res = append(res, *neigh)
  226. }
  227. return res, nil
  228. }
  229. func NeighDeserialize(m []byte) (*Neigh, error) {
  230. msg := deserializeNdmsg(m)
  231. neigh := Neigh{
  232. LinkIndex: int(msg.Index),
  233. Family: int(msg.Family),
  234. State: int(msg.State),
  235. Type: int(msg.Type),
  236. Flags: int(msg.Flags),
  237. }
  238. attrs, err := nl.ParseRouteAttr(m[msg.Len():])
  239. if err != nil {
  240. return nil, err
  241. }
  242. for _, attr := range attrs {
  243. switch attr.Attr.Type {
  244. case NDA_DST:
  245. neigh.IP = net.IP(attr.Value)
  246. case NDA_LLADDR:
  247. // BUG: Is this a bug in the netlink library?
  248. // #define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
  249. // #define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))
  250. attrLen := attr.Attr.Len - unix.SizeofRtAttr
  251. if attrLen == 4 {
  252. neigh.LLIPAddr = net.IP(attr.Value)
  253. } else if attrLen == 16 {
  254. // Can be IPv6 or FireWire HWAddr
  255. link, err := LinkByIndex(neigh.LinkIndex)
  256. if err == nil && link.Attrs().EncapType == "tunnel6" {
  257. neigh.IP = net.IP(attr.Value)
  258. } else {
  259. neigh.HardwareAddr = net.HardwareAddr(attr.Value)
  260. }
  261. } else {
  262. neigh.HardwareAddr = net.HardwareAddr(attr.Value)
  263. }
  264. case NDA_VLAN:
  265. neigh.Vlan = int(native.Uint16(attr.Value[0:2]))
  266. case NDA_VNI:
  267. neigh.VNI = int(native.Uint32(attr.Value[0:4]))
  268. case NDA_MASTER:
  269. neigh.MasterIndex = int(native.Uint32(attr.Value[0:4]))
  270. }
  271. }
  272. return &neigh, nil
  273. }
  274. // NeighSubscribe takes a chan down which notifications will be sent
  275. // when neighbors are added or deleted. Close the 'done' chan to stop subscription.
  276. func NeighSubscribe(ch chan<- NeighUpdate, done <-chan struct{}) error {
  277. return neighSubscribeAt(netns.None(), netns.None(), ch, done, nil, false)
  278. }
  279. // NeighSubscribeAt works like NeighSubscribe plus it allows the caller
  280. // to choose the network namespace in which to subscribe (ns).
  281. func NeighSubscribeAt(ns netns.NsHandle, ch chan<- NeighUpdate, done <-chan struct{}) error {
  282. return neighSubscribeAt(ns, netns.None(), ch, done, nil, false)
  283. }
  284. // NeighSubscribeOptions contains a set of options to use with
  285. // NeighSubscribeWithOptions.
  286. type NeighSubscribeOptions struct {
  287. Namespace *netns.NsHandle
  288. ErrorCallback func(error)
  289. ListExisting bool
  290. }
  291. // NeighSubscribeWithOptions work like NeighSubscribe but enable to
  292. // provide additional options to modify the behavior. Currently, the
  293. // namespace can be provided as well as an error callback.
  294. func NeighSubscribeWithOptions(ch chan<- NeighUpdate, done <-chan struct{}, options NeighSubscribeOptions) error {
  295. if options.Namespace == nil {
  296. none := netns.None()
  297. options.Namespace = &none
  298. }
  299. return neighSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting)
  300. }
  301. func neighSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- NeighUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error {
  302. s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_NEIGH)
  303. makeRequest := func(family int) error {
  304. req := pkgHandle.newNetlinkRequest(unix.RTM_GETNEIGH,
  305. unix.NLM_F_DUMP)
  306. infmsg := nl.NewIfInfomsg(family)
  307. req.AddData(infmsg)
  308. if err := s.Send(req); err != nil {
  309. return err
  310. }
  311. return nil
  312. }
  313. if err != nil {
  314. return err
  315. }
  316. if done != nil {
  317. go func() {
  318. <-done
  319. s.Close()
  320. }()
  321. }
  322. if listExisting {
  323. if err := makeRequest(unix.AF_UNSPEC); err != nil {
  324. return err
  325. }
  326. // We have to wait for NLMSG_DONE before making AF_BRIDGE request
  327. }
  328. go func() {
  329. defer close(ch)
  330. for {
  331. msgs, from, err := s.Receive()
  332. if err != nil {
  333. if cberr != nil {
  334. cberr(err)
  335. }
  336. return
  337. }
  338. if from.Pid != nl.PidKernel {
  339. if cberr != nil {
  340. cberr(fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel))
  341. }
  342. continue
  343. }
  344. for _, m := range msgs {
  345. if m.Header.Type == unix.NLMSG_DONE {
  346. if listExisting {
  347. // This will be called after handling AF_UNSPEC
  348. // list request, we have to wait for NLMSG_DONE
  349. // before making another request
  350. if err := makeRequest(unix.AF_BRIDGE); err != nil {
  351. if cberr != nil {
  352. cberr(err)
  353. }
  354. return
  355. }
  356. listExisting = false
  357. }
  358. continue
  359. }
  360. if m.Header.Type == unix.NLMSG_ERROR {
  361. native := nl.NativeEndian()
  362. error := int32(native.Uint32(m.Data[0:4]))
  363. if error == 0 {
  364. continue
  365. }
  366. if cberr != nil {
  367. cberr(syscall.Errno(-error))
  368. }
  369. return
  370. }
  371. neigh, err := NeighDeserialize(m.Data)
  372. if err != nil {
  373. if cberr != nil {
  374. cberr(err)
  375. }
  376. return
  377. }
  378. ch <- NeighUpdate{Type: m.Header.Type, Neigh: *neigh}
  379. }
  380. }
  381. }()
  382. return nil
  383. }