arping_bsd.go 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. // +build darwin freebsd openbsd
  2. package arping
  3. import (
  4. "errors"
  5. "fmt"
  6. "net"
  7. "os"
  8. "syscall"
  9. "time"
  10. )
  11. var bpf *os.File
  12. var bpfFd int
  13. var buflen int
  14. var bpfArpFilter = []syscall.BpfInsn{
  15. // make sure this is an arp packet
  16. *syscall.BpfStmt(syscall.BPF_LD+syscall.BPF_H+syscall.BPF_ABS, 12),
  17. *syscall.BpfJump(syscall.BPF_JMP+syscall.BPF_JEQ+syscall.BPF_K, 0x0806, 0, 1),
  18. // if we passed all the tests, ask for the whole packet.
  19. *syscall.BpfStmt(syscall.BPF_RET+syscall.BPF_K, -1),
  20. // otherwise, drop it.
  21. *syscall.BpfStmt(syscall.BPF_RET+syscall.BPF_K, 0),
  22. }
  23. func initialize(iface net.Interface) (err error) {
  24. verboseLog.Println("search available /dev/bpfX")
  25. for i := 0; i <= 10; i++ {
  26. bpfPath := fmt.Sprintf("/dev/bpf%d", i)
  27. bpf, err = os.OpenFile(bpfPath, os.O_RDWR, 0666)
  28. if err != nil {
  29. verboseLog.Printf(" open failed: %s - %s\n", bpfPath, err.Error())
  30. } else {
  31. verboseLog.Printf(" open success: %s\n", bpfPath)
  32. break
  33. }
  34. }
  35. bpfFd = int(bpf.Fd())
  36. if bpfFd == -1 {
  37. return errors.New("unable to open /dev/bpfX")
  38. }
  39. if err := syscall.SetBpfInterface(bpfFd, iface.Name); err != nil {
  40. return err
  41. }
  42. if err := syscall.SetBpfImmediate(bpfFd, 1); err != nil {
  43. return err
  44. }
  45. buflen, err = syscall.BpfBuflen(bpfFd)
  46. if err != nil {
  47. return err
  48. }
  49. if err := syscall.SetBpf(bpfFd, bpfArpFilter); err != nil {
  50. return err
  51. }
  52. if err := syscall.FlushBpf(bpfFd); err != nil {
  53. return err
  54. }
  55. return nil
  56. }
  57. func send(request arpDatagram) (time.Time, error) {
  58. _, err := syscall.Write(bpfFd, request.MarshalWithEthernetHeader())
  59. return time.Now(), err
  60. }
  61. func receive() (arpDatagram, time.Time, error) {
  62. buffer := make([]byte, buflen)
  63. n, err := syscall.Read(bpfFd, buffer)
  64. if err != nil {
  65. return arpDatagram{}, time.Now(), err
  66. }
  67. // skip 26 bytes bpf header + 14 bytes ethernet header
  68. return parseArpDatagram(buffer[40:n]), time.Now(), nil
  69. }
  70. func deinitialize() error {
  71. return bpf.Close()
  72. }