mirror of
https://github.com/Mo3he/Axis_Cam_Tailscale.git
synced 2026-08-16 20:26:46 +00:00
178 lines
5.7 KiB
Bash
178 lines
5.7 KiB
Bash
#!/bin/sh
|
|
# Tailscale VPN run script — called by the param_bridge C binary.
|
|
# Config is sourced from $STATE_DIR/params.conf (written by param_bridge).
|
|
# $1 selects the variant: "standard" (userspace networking + local proxies)
|
|
# or "root" (kernel networking, no local proxy). Defaults to "standard".
|
|
VARIANT="${1:-standard}"
|
|
|
|
killall tailscaled 2>/dev/null || true
|
|
|
|
APP_DIR="/usr/local/packages/Tailscale_VPN"
|
|
STATE_DIR="$APP_DIR/localdata"
|
|
TAILSCALED_PATH="$APP_DIR/lib/tailscaled"
|
|
TAILSCALE_PATH="$APP_DIR/lib/tailscale"
|
|
SOCKET_PATH="$STATE_DIR/tailscaled.sock"
|
|
|
|
mkdir -p "$STATE_DIR"
|
|
chmod 755 $TAILSCALED_PATH
|
|
chmod 755 $TAILSCALE_PATH
|
|
|
|
# Defaults — overridden by sourcing params.conf written by param_bridge
|
|
CUSTOM_SERVER=""
|
|
AUTH_KEY=""
|
|
CONF_HTTP="8080"
|
|
CONF_SOCKS="1080"
|
|
ACCEPT_DNS="false"
|
|
ACCEPT_ROUTES="false"
|
|
ADVERTISE_ROUTES=""
|
|
|
|
if [ -f "$STATE_DIR/params.conf" ]; then
|
|
. "$STATE_DIR/params.conf"
|
|
fi
|
|
|
|
if [ "$VARIANT" = "root" ]; then
|
|
logger -t "Tailscale_VPN" "Starting (root mode): custom_server=${CUSTOM_SERVER:-(default)}"
|
|
else
|
|
logger -t "Tailscale_VPN" "Starting: http_port=$CONF_HTTP socks_port=$CONF_SOCKS custom_server=${CUSTOM_SERVER:-(default)}"
|
|
|
|
# Check whether a TCP port is already bound
|
|
is_port_in_use() {
|
|
local port=$1
|
|
local hex_port
|
|
hex_port=$(printf '%04X' "$port")
|
|
grep -q ":${hex_port} " /proc/net/tcp 2>/dev/null && return 0
|
|
grep -q ":${hex_port} " /proc/net/tcp6 2>/dev/null && return 0
|
|
return 1
|
|
}
|
|
|
|
if is_port_in_use "$CONF_HTTP"; then
|
|
logger -t "Tailscale_VPN" "ERROR: HTTP proxy port $CONF_HTTP is already in use. Change it in Settings."
|
|
exit 1
|
|
fi
|
|
if is_port_in_use "$CONF_SOCKS"; then
|
|
logger -t "Tailscale_VPN" "ERROR: SOCKS5 port $CONF_SOCKS is already in use. Change it in Settings."
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
logger -t "Tailscale_VPN" "Starting tailscaled daemon"
|
|
if [ "$VARIANT" = "root" ]; then
|
|
$TAILSCALED_PATH \
|
|
--state="$STATE_DIR/tailscaled.state" \
|
|
--socket=$SOCKET_PATH \
|
|
>/dev/null 2>&1 &
|
|
else
|
|
$TAILSCALED_PATH \
|
|
--state="$STATE_DIR/tailscaled.state" \
|
|
--socket=$SOCKET_PATH \
|
|
--socks5-server=localhost:$CONF_SOCKS \
|
|
--outbound-http-proxy-listen=localhost:$CONF_HTTP \
|
|
--tun=userspace-networking \
|
|
>/dev/null 2>&1 &
|
|
fi
|
|
TAILSCALED_PID=$!
|
|
|
|
sleep 2
|
|
|
|
TAILSCALE_CMD="$TAILSCALE_PATH --socket=$SOCKET_PATH up --reset --hostname=$(hostname)"
|
|
|
|
if [ -n "$CUSTOM_SERVER" ]; then
|
|
TAILSCALE_CMD="$TAILSCALE_CMD --login-server $CUSTOM_SERVER"
|
|
fi
|
|
|
|
if [ -n "$AUTH_KEY" ]; then
|
|
TAILSCALE_CMD="$TAILSCALE_CMD --authkey $AUTH_KEY"
|
|
fi
|
|
|
|
if [ "$ACCEPT_DNS" = "true" ]; then
|
|
TAILSCALE_CMD="$TAILSCALE_CMD --accept-dns=true"
|
|
fi
|
|
|
|
if [ "$ACCEPT_ROUTES" = "true" ]; then
|
|
TAILSCALE_CMD="$TAILSCALE_CMD --accept-routes=true"
|
|
fi
|
|
|
|
# Advertise LAN subnets so this camera acts as a subnet router. Comma-separated
|
|
# CIDRs (e.g. 192.168.1.0/24,10.0.0.0/8). In userspace-networking mode the
|
|
# tailscaled netstack forwards tailnet traffic to these subnets, so no kernel IP
|
|
# forwarding is required. In kernel-networking (root) mode the host must
|
|
# forward packets between the tailnet and the LAN, so enable IP forwarding.
|
|
# Routes must still be approved in the Tailscale admin console either way.
|
|
if [ -n "$ADVERTISE_ROUTES" ]; then
|
|
if [ "$VARIANT" = "root" ]; then
|
|
echo 1 >/proc/sys/net/ipv4/ip_forward 2>/dev/null || true
|
|
echo 1 >/proc/sys/net/ipv6/conf/all/forwarding 2>/dev/null || true
|
|
fi
|
|
TAILSCALE_CMD="$TAILSCALE_CMD --advertise-routes=$ADVERTISE_ROUTES"
|
|
fi
|
|
|
|
# Run `tailscale up` in the background and act on its outcome. If the node needs
|
|
# (re-)authentication, `up` blocks until the user logs in; backgrounding it
|
|
# ensures the status publisher below keeps running so the UI can surface the
|
|
# login URL (tailscaled reports BackendState=NeedsLogin + AuthURL while waiting).
|
|
# NOTE: `up` runs synchronously *inside* this backgrounded block so its real exit
|
|
# code is captured directly. We must NOT background `up` separately and `wait`
|
|
# for it from here, because in POSIX sh `wait` only works on children of the
|
|
# current shell — a subshell waiting on the parent's child returns 127.
|
|
{
|
|
eval "$TAILSCALE_CMD"
|
|
up_exit=$?
|
|
if [ "$up_exit" -eq 0 ]; then
|
|
if [ "$VARIANT" = "root" ]; then
|
|
logger -t "Tailscale_VPN" "Tailscale VPN is running (root mode)"
|
|
else
|
|
logger -t "Tailscale_VPN" "Tailscale VPN is running"
|
|
fi
|
|
# Auth succeeded with a one-time auth key — signal param_bridge to clear it
|
|
if [ -n "$AUTH_KEY" ]; then
|
|
: >"$STATE_DIR/authkey_clear"
|
|
fi
|
|
else
|
|
logger -t "Tailscale_VPN" "ERROR: tailscale up failed (exit $up_exit)"
|
|
fi
|
|
} &
|
|
TAILSCALE_UP_PID=$!
|
|
|
|
if [ "$VARIANT" != "root" ]; then
|
|
logger -t "Tailscale_VPN" "HTTP/HTTPS proxy: http://127.0.0.1:$CONF_HTTP"
|
|
logger -t "Tailscale_VPN" "SOCKS5 proxy: 127.0.0.1:$CONF_SOCKS"
|
|
fi
|
|
|
|
# Publish tailscale's real backend state as JSON for the web UI to consume.
|
|
# This is the authoritative connection signal (BackendState / Self.Online /
|
|
# TailscaleIPs / AuthURL) instead of scraping syslog. Served statically at
|
|
# /local/Tailscale_VPN/status.json.
|
|
STATUS_FILE="$APP_DIR/html/status.json"
|
|
|
|
publish_status() {
|
|
if "$TAILSCALE_PATH" --socket="$SOCKET_PATH" status --json >"$STATUS_FILE.tmp" 2>/dev/null; then
|
|
mv "$STATUS_FILE.tmp" "$STATUS_FILE" 2>/dev/null
|
|
chmod 644 "$STATUS_FILE" 2>/dev/null
|
|
else
|
|
rm -f "$STATUS_FILE.tmp" 2>/dev/null
|
|
fi
|
|
}
|
|
|
|
status_loop() {
|
|
while true; do
|
|
publish_status
|
|
sleep 5
|
|
done
|
|
}
|
|
status_loop &
|
|
STATUS_LOOP_PID=$!
|
|
|
|
# Clean up the status writer, up watcher, daemon and published status on
|
|
# stop/restart so param_bridge (which signals this script) leaves no orphans or
|
|
# stale state.
|
|
cleanup() {
|
|
[ -n "$STATUS_LOOP_PID" ] && kill "$STATUS_LOOP_PID" 2>/dev/null
|
|
[ -n "$TAILSCALE_UP_PID" ] && kill "$TAILSCALE_UP_PID" 2>/dev/null
|
|
[ -n "$TAILSCALED_PID" ] && kill "$TAILSCALED_PID" 2>/dev/null
|
|
rm -f "$STATUS_FILE" 2>/dev/null
|
|
exit 0
|
|
}
|
|
trap cleanup TERM INT
|
|
|
|
wait $TAILSCALED_PID
|