package app import ( "fmt" "strings" "time" ) func (egressSystemProvider) Probe(_ egressScopeTarget) (string, error) { return egressProbeExternalIP() } func (egressAdGuardProvider) Probe(_ egressScopeTarget) (string, error) { stdout, stderr, code, err := runCommandTimeout(2*time.Second, "systemctl", "is-active", adgvpnUnit) state := strings.ToLower(strings.TrimSpace(stdout)) if state != "active" || err != nil || code != 0 { return "", transportCommandError("systemctl is-active "+adgvpnUnit, stdout, stderr, code, err) } iface, _ := resolveTrafficIface(loadTrafficModeState().PreferredIface) if iface = strings.TrimSpace(iface); iface == "" { return "", fmt.Errorf("adguardvpn interface is not resolved") } if !ifaceExists(iface) { return "", fmt.Errorf("adguardvpn interface %q is not available", iface) } return egressProbeExternalIPViaInterface(iface) } func (egressTransportProvider) Probe(target egressScopeTarget) (string, error) { id := sanitizeID(target.SourceID) if id == "" { return "", fmt.Errorf("invalid transport source id") } transportMu.Lock() st := loadTransportClientsState() idx := findTransportClientIndex(st.Items, id) var client TransportClient if idx >= 0 { client = st.Items[idx] } transportMu.Unlock() if idx < 0 { return "", fmt.Errorf("transport client %q not found", id) } if !client.Enabled { return "", fmt.Errorf("transport client %q is disabled", id) } if normalizeTransportStatus(client.Status) == TransportClientDown { backend := selectTransportBackend(client) live := backend.Health(client) if normalizeTransportStatus(live.Status) != TransportClientUp { msg := strings.TrimSpace(live.Message) if msg == "" { msg = fmt.Sprintf("transport client %q is down", id) } return "", fmt.Errorf("%s", msg) } client.Status = TransportClientUp } if transportNetnsEnabled(client) { ns := transportNetnsName(client) if strings.TrimSpace(ns) == "" { return "", fmt.Errorf("transport client %q netns is enabled but netns_name is empty", id) } if client.Kind == TransportClientSingBox { proxyURL := egressSingBoxSOCKSProxyURL(client) if proxyURL == "" { return "", fmt.Errorf("proxy probe failed: singbox socks inbound not found") } // For SingBox in netns we must use tunnel egress probe (SOCKS inbound -> outbound proxy). // Direct netns probe is intentionally not used: in selective mode it may return AdGuard/system IP. ip, err := egressProbeExternalIPInNetnsViaProxy(client, ns, proxyURL) if err == nil { return ip, nil } return "", fmt.Errorf("proxy probe failed: %v", err) } ip, err := egressProbeExternalIPInNetns(client, ns) if err == nil { return ip, nil } return "", err } iface := strings.TrimSpace(client.Iface) if iface != "" && ifaceExists(iface) { return egressProbeExternalIPViaInterface(iface) } return egressProbeExternalIP() }