Add Harbor Gateway auto-detection for client routing
All checks were successful
Build and Deploy Gateway / build-and-push (push) Successful in 13s
Build and Deploy Gateway / deploy (push) Successful in 1s

This commit is contained in:
2026-07-11 15:02:33 +03:00
parent 0a1aa8aed3
commit 51312d51cd
17 changed files with 717 additions and 165 deletions

View File

@@ -0,0 +1,46 @@
#!/usr/bin/env bash
set -euo pipefail
export LC_ALL=C
RUNTIME_DIR="${HARBOR_RUNTIME_DIR:-$HOME/.vpn-proxy-client/.runtime}"
STATE_FILE="$RUNTIME_DIR/network.json"
ROUTE_BIN="${HARBOR_ROUTE_BIN:-/sbin/route}"
ARP_BIN="${HARBOR_ARP_BIN:-/usr/sbin/arp}"
NETSTAT_BIN="${HARBOR_NETSTAT_BIN:-/usr/sbin/netstat}"
route_info="$($ROUTE_BIN -n get default 2>/dev/null || true)"
gateway="$(awk '/^[[:space:]]*gateway:/{print $2; exit}' <<<"$route_info")"
network_interface="$(awk '/^[[:space:]]*interface:/{print $2; exit}' <<<"$route_info")"
if [[ -z "$gateway" || -z "$network_interface" ]]; then
read -r gateway network_interface < <(
"$NETSTAT_BIN" -rn -f inet 2>/dev/null \
| awk '$1 == "default" && $2 ~ /^[0-9]+\./ { print $2, $4; exit }'
) || true
fi
if [[ ! "$gateway" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
gateway=""
network_interface=""
fi
if [[ ! "$network_interface" =~ ^[a-zA-Z0-9._-]{1,32}$ ]]; then
network_interface=""
fi
mac=""
if [[ -n "$gateway" ]]; then
mac="$($ARP_BIN -n "$gateway" 2>/dev/null | awk '/ at /{print $4; exit}' || true)"
if [[ ! "$mac" =~ ^[a-fA-F0-9]{2}(:[a-fA-F0-9]{2}){5}$ ]]; then
mac=""
else
mac="$(printf '%s' "$mac" | tr '[:upper:]' '[:lower:]')"
fi
fi
mkdir -p "$RUNTIME_DIR"
tmp="$(mktemp "${STATE_FILE}.XXXXXX")"
trap 'rm -f "$tmp"' EXIT
printf '{"gateway":"%s","interface":"%s","mac":"%s","observedAt":"%s"}\n' \
"$gateway" "$network_interface" "$mac" "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" > "$tmp"
mv "$tmp" "$STATE_FILE"

View File

@@ -9,6 +9,7 @@ DEFAULT_PROXY_PORT="8082"
REQUESTED_PROXY_PORT="${VPN_PROXY_CLIENT_PORT:-}"
REQUESTED_UI_PORT="${VPN_PROXY_CLIENT_UI_PORT:-${CLIENT_UI_PORT:-}}"
CLIENT_CONTAINER_NAME="vpn-proxy-client"
NETWORK_MONITOR_LABEL="com.dokril.harbor-connect.network"
log() {
printf '[vpn-proxy-client] %s\n' "$*"
@@ -175,6 +176,54 @@ wait_for_client_ui() {
die "client UI is not ready; see Docker status and logs above"
}
xml_escape() {
sed -e 's/&/\&amp;/g' -e 's/</\&lt;/g' -e 's/>/\&gt;/g' -e 's/"/\&quot;/g'
}
install_network_monitor() {
local launch_agents_dir="$HOME/Library/LaunchAgents"
local plist_path="$launch_agents_dir/${NETWORK_MONITOR_LABEL}.plist"
local escaped_script_path
local escaped_runtime_dir
local user_domain="gui/$(id -u)"
escaped_script_path="$(printf '%s' "$INSTALL_DIR/scripts/harbor-network-monitor.sh" | xml_escape)"
escaped_runtime_dir="$(printf '%s' "$INSTALL_DIR/.runtime" | xml_escape)"
mkdir -p "$INSTALL_DIR/.runtime" "$launch_agents_dir"
cat > "$plist_path" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>${NETWORK_MONITOR_LABEL}</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>${escaped_script_path}</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>HARBOR_RUNTIME_DIR</key>
<string>${escaped_runtime_dir}</string>
</dict>
<key>RunAtLoad</key>
<true/>
<key>StartInterval</key>
<integer>5</integer>
<key>ProcessType</key>
<string>Background</string>
</dict>
</plist>
EOF
/bin/bash "$INSTALL_DIR/scripts/harbor-network-monitor.sh"
launchctl bootout "$user_domain" "$plist_path" >/dev/null 2>&1 || true
launchctl bootstrap "$user_domain" "$plist_path"
log "automatic Gateway detection enabled"
}
set_env_value() {
local key="$1"
local value="$2"
@@ -247,6 +296,8 @@ set_env_value PROXY_PORT "$PROXY_PORT"
log "UI port: http://127.0.0.1:${UI_PORT}"
log "proxy port: 127.0.0.1:${PROXY_PORT}"
install_network_monitor
log "building and starting Docker client"
docker compose -f "$COMPOSE_FILE" up -d --build
wait_for_client_ui