arp_freebsd.go 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  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 Interfaces, hws HardwareAddrStates) (present bool, err error) {
  41. as := make(map[string]bool, len(hws))
  42. for hw := range hws {
  43. as[hw] = false
  44. }
  45. cmd := exec.CommandContext(ctx, a.cmd, "--libxo=json", "-an")
  46. b, err := cmd.Output()
  47. if err != nil {
  48. return
  49. }
  50. o := &arpOutput{}
  51. err = json.Unmarshal(b, o)
  52. if err != nil {
  53. return
  54. }
  55. if o.Version != arpOutputVersion {
  56. err = fmt.Errorf("arp output version mismatch (got %v, expected %v)", o.Version, arpOutputVersion)
  57. return
  58. }
  59. for _, e := range o.ARP.Cache {
  60. if ifs[e.Interface] {
  61. var hwa net.HardwareAddr
  62. hwa, err = net.ParseMAC(e.MACAddress)
  63. if err != nil {
  64. return
  65. }
  66. hw := hwa.String()
  67. if _, ok := as[hw]; ok {
  68. ok, err = a.arping.Ping(ctx, e.Interface, hw, e.IPAddress)
  69. if err != nil {
  70. return
  71. }
  72. as[hw] = ok
  73. }
  74. }
  75. }
  76. for hw, ok := range as {
  77. hws[hw].Set(ok)
  78. if ok {
  79. present = true
  80. }
  81. }
  82. return
  83. }