arp_freebsd.go 1.7 KB

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