arp_freebsd.go 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. package neighbors
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "net"
  7. "os/exec"
  8. )
  9. const (
  10. arpOutputVersion = "1"
  11. )
  12. type (
  13. arp struct {
  14. cmd string
  15. arping ARPing
  16. }
  17. arpOutput struct {
  18. Version string `json:"__version"`
  19. ARP struct {
  20. Cache []arpEntry `json:"arp-cache"`
  21. } `json:"arp"`
  22. }
  23. arpEntry struct {
  24. IPAddress string `json:"ip-address"`
  25. MACAddress string `json:"mac-address"`
  26. Interface string `json:"interface"`
  27. }
  28. )
  29. func NewARP(count uint) (ARP, error) {
  30. cmd, err := exec.LookPath("arp")
  31. if err != nil {
  32. return nil, err
  33. }
  34. arping, err := NewARPing(count)
  35. if err != nil {
  36. return nil, err
  37. }
  38. return &arp{cmd: cmd, arping: arping}, nil
  39. }
  40. func (a *arp) Present(ctx context.Context, ifs map[string]bool, hws map[string]bool) (ok bool, err error) {
  41. cmd := exec.CommandContext(ctx, a.cmd, "--libxo=json", "-an")
  42. b, err := cmd.Output()
  43. if err != nil {
  44. return
  45. }
  46. o := &arpOutput{}
  47. err = json.Unmarshal(b, o)
  48. if err != nil {
  49. return
  50. }
  51. if o.Version != arpOutputVersion {
  52. err = fmt.Errorf("arp output version mismatch (got %v, expected %v)", o.Version, arpOutputVersion)
  53. return
  54. }
  55. for _, e := range o.ARP.Cache {
  56. if ifs[e.Interface] {
  57. var hwa net.HardwareAddr
  58. hwa, err = net.ParseMAC(e.MACAddress)
  59. if err != nil {
  60. return
  61. }
  62. hw := hwa.String()
  63. if hws[hw] {
  64. ok, err = a.arping.Ping(ctx, e.Interface, hw, e.IPAddress)
  65. if ok || err != nil {
  66. return
  67. }
  68. }
  69. }
  70. }
  71. return
  72. }