123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 |
- package neighbors
- import (
- "bufio"
- "bytes"
- "context"
- "errors"
- "fmt"
- "os/exec"
- "regexp"
- "goa.design/clue/log"
- )
- type (
- ARPing interface {
- Ping(ctx context.Context, ifi, hw, ip string) (bool, error)
- Count(count uint)
- }
- arping struct {
- arpingCmd, sudoCmd, count string
- }
- )
- func NewARPing(count uint) (ARPing, error) {
- arpingCmd, err := exec.LookPath("arping")
- if err != nil {
- return nil, err
- }
- cmd := exec.Command(arpingCmd, "--help")
- b, err := cmd.Output()
- if err != nil {
- return nil, fmt.Errorf(`incompatible "arping" command (%w)`, err)
- }
- ok, err := regexp.Match("^ARPing ", b)
- if err != nil {
- return nil, err
- }
- if !ok {
- r := bufio.NewReaderSize(bytes.NewReader(b), 32)
- l, p, err := r.ReadLine()
- if err != nil {
- return nil, fmt.Errorf(`incompatible "arping" command (%w)`, err)
- }
- var e string
- if p {
- e = "\u2026"
- }
- return nil, fmt.Errorf(`incompatible "arping" command (%s%v)`, l, e)
- }
- sudoCmd, err := exec.LookPath("sudo")
- if err != nil {
- return nil, err
- }
- return &arping{
- arpingCmd: arpingCmd,
- sudoCmd: sudoCmd,
- count: fmt.Sprint(count),
- }, nil
- }
- func (a *arping) Ping(ctx context.Context, ifi, hw, ip string) (ok bool, err error) {
- cmd := exec.CommandContext(ctx, a.sudoCmd, a.arpingCmd, "-c", a.count, "-i", ifi, "-t", hw, "-q", ip)
- log.Debug(ctx, log.KV{K: "cmd", V: cmd})
- err = cmd.Run()
- if err == nil {
- ok = true
- } else {
- var exitError *exec.ExitError
- if errors.As(err, &exitError) && len(exitError.Stderr) == 0 {
- err = nil
- } else {
- return
- }
- }
- log.Debug(ctx, log.KV{K: "cmd", V: cmd}, log.KV{K: "ok", V: ok})
- return
- }
- func (a *arping) Count(count uint) {
- a.count = fmt.Sprint(count)
- }
|