Browse Source

Detect incompatible arping commands such as iputils-arping

Douglas Thrift 1 year ago
parent
commit
a2dcf6a06c
1 changed files with 32 additions and 4 deletions
  1. 32 4
      neighbors/arping.go

+ 32 - 4
neighbors/arping.go

@@ -1,10 +1,13 @@
 package neighbors
 
 import (
+	"bufio"
+	"bytes"
 	"context"
 	"errors"
 	"fmt"
 	"os/exec"
+	"regexp"
 )
 
 type (
@@ -13,26 +16,51 @@ type (
 	}
 
 	arping struct {
-		cmd, sudoCmd, count string
+		arpingCmd, sudoCmd, count string
 	}
 )
 
 func NewARPing(count uint) (ARPing, error) {
-	cmd, err := exec.LookPath("arping")
+	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{cmd: cmd, sudoCmd: sudoCmd, count: fmt.Sprint(count)}, nil
+	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.cmd, "-c", a.count, "-i", ifi, "-t", hw, "-q", ip)
+	cmd := exec.CommandContext(ctx, a.sudoCmd, a.arpingCmd, "-c", a.count, "-i", ifi, "-t", hw, "-q", ip)
 	err = cmd.Run()
 	if err == nil {
 		ok = true