Files
AetherForge/agent/client/connectivity_probe.go
AetherForge 5fc601b564 feat: fleet ops, KEV scan, tunnels, beacon fallback, persistence
Extend owned-fleet control with scheduled tasks, audit log, file browser,
HTTPS beacon when WS drops, protocol tunnels, registry/autostart forge
options, KEV exposure in full sys check with Telegram alerts, and UI/tests.
2026-06-04 09:34:33 -07:00

94 lines
2.4 KiB
Go

package client
import (
"fmt"
"net"
"net/url"
"strings"
"time"
)
// ConnectivityProbeReport is diagnostic-only reachability (not a C2 channel).
type ConnectivityProbeReport struct {
C2Host string `json:"c2_host"`
C2DNSOK bool `json:"c2_dns_ok"`
C2DNSAddrs []string `json:"c2_dns_addrs,omitempty"`
C2TCPOK bool `json:"c2_tcp_ok"`
C2TCPError string `json:"c2_tcp_error,omitempty"`
PoolHost string `json:"pool_host,omitempty"`
PoolDNSOK bool `json:"pool_dns_ok,omitempty"`
PoolDNSAddrs []string `json:"pool_dns_addrs,omitempty"`
PoolTCPOK bool `json:"pool_tcp_ok,omitempty"`
PoolTCPError string `json:"pool_tcp_error,omitempty"`
}
func runConnectivityProbe(serverURL, poolHost string, poolPort int) ConnectivityProbeReport {
report := ConnectivityProbeReport{}
host, port, err := hostPortFromServerURL(serverURL)
if err != nil {
report.C2Host = serverURL
report.C2TCPError = err.Error()
return report
}
report.C2Host = net.JoinHostPort(host, port)
report.C2DNSOK, report.C2DNSAddrs = probeDNSResolve(host)
report.C2TCPOK, report.C2TCPError = probeTCPConnect(host, port)
if poolHost != "" {
pport := poolPort
if pport <= 0 {
pport = 3333
}
pportStr := fmt.Sprintf("%d", pport)
report.PoolHost = net.JoinHostPort(poolHost, pportStr)
report.PoolDNSOK, report.PoolDNSAddrs = probeDNSResolve(poolHost)
report.PoolTCPOK, report.PoolTCPError = probeTCPConnect(poolHost, pportStr)
}
return report
}
func hostPortFromServerURL(serverURL string) (host, port string, err error) {
raw := strings.TrimSpace(serverURL)
if raw == "" {
return "", "", fmt.Errorf("empty server URL")
}
if !strings.Contains(raw, "://") {
raw = "http://" + raw
}
u, err := url.Parse(raw)
if err != nil {
return "", "", err
}
host = u.Hostname()
port = u.Port()
if port == "" {
if u.Scheme == "https" {
port = "443"
} else {
port = "80"
}
}
if host == "" {
return "", "", fmt.Errorf("no host in server URL")
}
return host, port, nil
}
func probeDNSResolve(host string) (bool, []string) {
addrs, err := net.LookupHost(host)
if err != nil || len(addrs) == 0 {
return false, nil
}
return true, addrs
}
func probeTCPConnect(host, port string) (bool, string) {
addr := net.JoinHostPort(host, port)
conn, err := net.DialTimeout("tcp", addr, 5*time.Second)
if err != nil {
return false, err.Error()
}
_ = conn.Close()
return true, ""
}