165 lines
4.5 KiB
Go
165 lines
4.5 KiB
Go
package app
|
|
|
|
import (
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
transportPolicyTargetAdGuardID = "adguardvpn"
|
|
transportPolicyTargetAdGuardIfaceID = transportDefaultIfaceID
|
|
transportPolicyTargetAdGuardTable = "agvpn"
|
|
)
|
|
|
|
var transportPolicyTargetAdGuardAllowedActions = []string{"start", "stop", "restart"}
|
|
|
|
func isTransportPolicyVirtualClientID(id string) bool {
|
|
return sanitizeID(id) == transportPolicyTargetAdGuardID
|
|
}
|
|
|
|
func isTransportPolicyVirtualClient(client TransportClient) bool {
|
|
if isTransportPolicyVirtualClientID(client.ID) {
|
|
return true
|
|
}
|
|
return strings.EqualFold(strings.TrimSpace(string(client.Kind)), transportPolicyTargetAdGuardID)
|
|
}
|
|
|
|
func resolveTransportPolicyVirtualClient(id string) (TransportClient, bool) {
|
|
if !isTransportPolicyVirtualClientID(id) {
|
|
return TransportClient{}, false
|
|
}
|
|
return buildTransportPolicyAdGuardTarget()
|
|
}
|
|
|
|
func transportPolicyPersistableClients(items []TransportClient) []TransportClient {
|
|
if len(items) == 0 {
|
|
return nil
|
|
}
|
|
out := make([]TransportClient, 0, len(items))
|
|
for _, it := range items {
|
|
if isTransportPolicyVirtualClient(it) {
|
|
continue
|
|
}
|
|
out = append(out, it)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func transportPolicyClientsWithVirtualTargets(base []TransportClient) []TransportClient {
|
|
out := append([]TransportClient(nil), base...)
|
|
for i := range out {
|
|
out[i].ID = sanitizeID(out[i].ID)
|
|
}
|
|
if adg, ok := buildTransportPolicyAdGuardTarget(); ok {
|
|
if idx := findTransportClientIndex(out, adg.ID); idx >= 0 {
|
|
out[idx] = adg
|
|
} else {
|
|
out = append(out, adg)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func buildTransportPolicyAdGuardTarget() (TransportClient, bool) {
|
|
now := time.Now().UTC()
|
|
|
|
stdout, _, _, err := runCommandTimeout(1500*time.Millisecond, "systemctl", "is-active", adgvpnUnit)
|
|
unitState := strings.TrimSpace(stdout)
|
|
if err != nil && unitState == "" {
|
|
return TransportClient{}, false
|
|
}
|
|
|
|
word, raw := parseAutoloopStatus(tailFile(autoloopLogPath, 120))
|
|
return buildTransportPolicyAdGuardTargetFromObservation(unitState, word, raw, now), true
|
|
}
|
|
|
|
func buildTransportPolicyAdGuardTargetFromObservation(unitState, statusWord, raw string, observedAt time.Time) TransportClient {
|
|
ts := observedAt.UTC().Format(time.RFC3339)
|
|
status := adGuardPolicyTargetStatus(unitState, statusWord)
|
|
iface := adGuardPolicyTargetIface(raw, status)
|
|
|
|
lastError := ""
|
|
if status == TransportClientDown || status == TransportClientDegraded {
|
|
msg := strings.TrimSpace(unitState)
|
|
if msg == "" {
|
|
msg = strings.TrimSpace(statusWord)
|
|
}
|
|
lastError = msg
|
|
}
|
|
|
|
return TransportClient{
|
|
ID: transportPolicyTargetAdGuardID,
|
|
Name: "AdGuard VPN",
|
|
Kind: TransportClientKind(transportPolicyTargetAdGuardID),
|
|
Enabled: true,
|
|
Status: status,
|
|
IfaceID: transportPolicyTargetAdGuardIfaceID,
|
|
Iface: iface,
|
|
RoutingTable: transportPolicyTargetAdGuardTable,
|
|
Capabilities: []string{"vpn", "systemd", "autoloop"},
|
|
Health: TransportClientHealth{
|
|
LastCheck: ts,
|
|
LastError: lastError,
|
|
},
|
|
Runtime: TransportClientRuntime{
|
|
Backend: "adguard",
|
|
AllowedActions: append([]string(nil), transportPolicyTargetAdGuardAllowedActions...),
|
|
LastAction: "observe",
|
|
LastActionAt: ts,
|
|
},
|
|
UpdatedAt: ts,
|
|
}
|
|
}
|
|
|
|
func adGuardPolicyTargetStatus(unitState, statusWord string) TransportClientStatus {
|
|
word := strings.ToUpper(strings.TrimSpace(statusWord))
|
|
switch word {
|
|
case "CONNECTED":
|
|
return TransportClientUp
|
|
case "RECONNECTING":
|
|
return TransportClientStarting
|
|
case "DISCONNECTED":
|
|
return TransportClientDown
|
|
case "ERROR":
|
|
return TransportClientDegraded
|
|
}
|
|
|
|
state := strings.ToLower(strings.TrimSpace(unitState))
|
|
switch state {
|
|
case "active":
|
|
return TransportClientUp
|
|
case "activating", "reloading":
|
|
return TransportClientStarting
|
|
case "failed", "inactive", "deactivating":
|
|
return TransportClientDown
|
|
default:
|
|
return TransportClientDown
|
|
}
|
|
}
|
|
|
|
func adGuardPolicyTargetIface(raw string, status TransportClientStatus) string {
|
|
v := strings.TrimSpace(raw)
|
|
if v != "" {
|
|
low := strings.ToLower(v)
|
|
needle := "running on "
|
|
if idx := strings.LastIndex(low, needle); idx >= 0 {
|
|
tail := strings.TrimSpace(v[idx+len(needle):])
|
|
if tail != "" {
|
|
iface := strings.Trim(tail, ".,;:()[]{}")
|
|
if parts := strings.Fields(iface); len(parts) > 0 {
|
|
if strings.TrimSpace(parts[0]) != "" {
|
|
return strings.TrimSpace(parts[0])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if iface, _ := resolveTrafficIface(loadTrafficModeState().PreferredIface); strings.TrimSpace(iface) != "" {
|
|
return strings.TrimSpace(iface)
|
|
}
|
|
if status == TransportClientUp || status == TransportClientStarting {
|
|
return "tun0"
|
|
}
|
|
return ""
|
|
}
|