arp_freebsd.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  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{
  40. cmd: cmd,
  41. arping: arping,
  42. }, nil
  43. }
  44. func (a *arp) Present(ctx context.Context, ifs Interfaces, state State, addrStates HardwareAddrStates) (err error) {
  45. as := make(map[string]bool, len(addrStates))
  46. for hw := range addrStates {
  47. as[hw] = false
  48. }
  49. cmd := exec.CommandContext(ctx, a.cmd, "--libxo=json", "-an")
  50. log.Debug(ctx, log.KV{K: "cmd", V: cmd})
  51. b, err := cmd.Output()
  52. if err != nil {
  53. return
  54. }
  55. o := &arpOutput{}
  56. err = json.Unmarshal(b, o)
  57. if err != nil {
  58. return
  59. }
  60. if o.Version != arpOutputVersion {
  61. err = fmt.Errorf("arp output version mismatch (got %v, expected %v)", o.Version, arpOutputVersion)
  62. return
  63. }
  64. for _, e := range o.ARP.Cache {
  65. log.Debug(ctx, log.KV{K: "IP address", V: e.IPAddress}, log.KV{K: "MAC address", V: e.MACAddress}, log.KV{K: "interface", V: e.Interface})
  66. if ifs[e.Interface] {
  67. var hwa net.HardwareAddr
  68. hwa, err = net.ParseMAC(e.MACAddress)
  69. if err != nil {
  70. return
  71. }
  72. hw := hwa.String()
  73. if _, ok := as[hw]; ok {
  74. ok, err = a.arping.Ping(ctx, e.Interface, hw, e.IPAddress)
  75. if err != nil {
  76. return
  77. }
  78. as[hw] = ok
  79. }
  80. }
  81. }
  82. present := false
  83. for hw, ok := range as {
  84. addrStates[hw].Set(ok)
  85. if ok {
  86. present = true
  87. }
  88. }
  89. state.Set(present)
  90. return
  91. }
  92. func (a *arp) Count(count uint) {
  93. a.arping.Count(count)
  94. }