Files
UpSnap/backend/networking/ping.go
2025-03-18 01:27:02 +01:00

94 lines
2.0 KiB
Go

package networking
import (
"errors"
"net"
"os"
"os/exec"
"runtime"
"strconv"
"syscall"
"time"
"github.com/pocketbase/pocketbase/core"
probing "github.com/prometheus-community/pro-bing"
)
func isNoRouteOrDownError(err error) bool {
opErr, ok := err.(*net.OpError)
if !ok {
return false
}
syscallErr, ok := opErr.Err.(*os.SyscallError)
if !ok {
return false
}
return syscallErr.Err == syscall.EHOSTUNREACH || syscallErr.Err == syscall.EHOSTDOWN
}
func PingDevice(device *core.Record) (bool, error) {
ping_cmd := device.GetString("ping_cmd")
if ping_cmd == "" {
pinger, err := probing.NewPinger(device.GetString("ip"))
if err != nil {
return false, err
}
pinger.Count = 1
pinger.Timeout = 500 * time.Millisecond
privileged := isRoot()
privilegedEnv := os.Getenv("UPSNAP_PING_PRIVILEGED")
if privilegedEnv != "" {
privileged, err = strconv.ParseBool(privilegedEnv)
if err != nil {
privileged = false
}
}
pinger.SetPrivileged(privileged)
err = pinger.Run()
if err != nil {
if isNoRouteOrDownError(err) {
return false, nil
}
return false, err
}
stats := pinger.Statistics()
return stats.PacketLoss == 0, nil
} else {
var shell string
var shell_arg string
if runtime.GOOS == "windows" {
shell = "cmd"
shell_arg = "/C"
} else {
shell = "/bin/sh"
shell_arg = "-c"
}
cmd := exec.Command(shell, shell_arg, ping_cmd)
err := cmd.Run()
return err == nil, err
}
}
func CheckPort(host string, port string) (bool, error) {
timeout := 500 * time.Millisecond
conn, err := net.DialTimeout("tcp", net.JoinHostPort(host, port), timeout)
if err != nil {
// treat "host unreachable", "connection refused" and "timeout" as no error
var netErr *net.OpError
if errors.As(err, &netErr) {
if errors.Is(netErr.Err, syscall.EHOSTUNREACH) ||
errors.Is(netErr.Err, syscall.ECONNREFUSED) ||
netErr.Timeout() {
return false, nil
}
}
return false, err
}
defer conn.Close()
return conn != nil, nil
}