arp_linux.go 1.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  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 map[string]bool, hws map[string]bool) (ok bool, err error) {
  31. cmd := exec.CommandContext(ctx, a.cmd, "-family", "inet", "-json", "neighbor", "show", "nud", "reachable")
  32. b, err := cmd.Output()
  33. if err != nil {
  34. return
  35. }
  36. var es []arpEntry
  37. err = json.Unmarshal(b, &es)
  38. for _, e := range es {
  39. if ifs[e.Interface] {
  40. var hwa net.HardwareAddr
  41. hwa, err = net.ParseMAC(e.MACAddress)
  42. if err != nil {
  43. return
  44. }
  45. hw := hwa.String()
  46. if hws[hw] {
  47. ok, err = a.arping.Ping(ctx, e.Interface, hw, e.IPAddress)
  48. if ok || err != nil {
  49. return
  50. }
  51. }
  52. }
  53. }
  54. return
  55. }