arp_linux.go 1.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. package neighbors
  2. import (
  3. "context"
  4. "encoding/json"
  5. "net"
  6. "os/exec"
  7. )
  8. type (
  9. arp struct {
  10. cmd string
  11. arping ARPing
  12. }
  13. arpEntry struct {
  14. IPAddress string `json:"dst"`
  15. MACAddress string `json:"lladdr"`
  16. Interface string `json:"dev"`
  17. }
  18. )
  19. func NewARP(count uint) (ARP, error) {
  20. cmd, err := exec.LookPath("ip")
  21. if err != nil {
  22. return nil, err
  23. }
  24. arping, err := NewARPing(count)
  25. if err != nil {
  26. return nil, err
  27. }
  28. return &arp{cmd: cmd, arping: arping}, nil
  29. }
  30. func (a *arp) Present(ctx context.Context, ifs Interfaces, hws HardwareAddrStates) (present bool, err error) {
  31. as := make(map[string]bool, len(hws))
  32. for hw := range hws {
  33. as[hw] = false
  34. }
  35. cmd := exec.CommandContext(ctx, a.cmd, "-family", "inet", "-json", "neighbor", "show", "nud", "reachable")
  36. b, err := cmd.Output()
  37. if err != nil {
  38. return
  39. }
  40. var es []arpEntry
  41. err = json.Unmarshal(b, &es)
  42. for _, e := range es {
  43. if ifs[e.Interface] {
  44. var hwa net.HardwareAddr
  45. hwa, err = net.ParseMAC(e.MACAddress)
  46. if err != nil {
  47. return
  48. }
  49. hw := hwa.String()
  50. if _, ok := as[hw]; ok {
  51. ok, err = a.arping.Ping(ctx, e.Interface, hw, e.IPAddress)
  52. if err != nil {
  53. return
  54. }
  55. as[hw] = ok
  56. }
  57. }
  58. }
  59. for hw, ok := range as {
  60. hws[hw].Set(ok)
  61. if ok {
  62. present = true
  63. }
  64. }
  65. return
  66. }