Add host routing watcher for cistech-tunnel (same pattern as rego-tunnel)
Some checks failed
Test / test (push) Has been cancelled
Some checks failed
Test / test (push) Has been cancelled
- Add shared/host-routing.sh with nft for NAT masquerade - Add shared/install-host-services.sh to set up systemd watcher - Add shared/uninstall-host-services.sh for cleanup - Add /runtime volume mount for trigger file - Update entrypoint.sh to trigger host routing when VPN connects Run install-host-services.sh on host after app install. Requires image rebuild for entrypoint changes. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,7 +16,8 @@
|
|||||||
"NOVNC_PORT": "6902"
|
"NOVNC_PORT": "6902"
|
||||||
},
|
},
|
||||||
"volumes": [
|
"volumes": [
|
||||||
{ "hostPath": "${APP_DATA_DIR}/data", "containerPath": "/root" }
|
{ "hostPath": "${APP_DATA_DIR}/data", "containerPath": "/root" },
|
||||||
|
{ "hostPath": "${APP_DATA_DIR}", "containerPath": "/runtime" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
123
apps/cistech-tunnel/shared/host-routing.sh
Normal file
123
apps/cistech-tunnel/shared/host-routing.sh
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Host routing script for cistech-tunnel
|
||||||
|
# Routes target subnets through the VPN container
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ACTION="${1:-start}"
|
||||||
|
|
||||||
|
# Fixed configuration
|
||||||
|
CONTAINER_IP="172.30.0.10"
|
||||||
|
BRIDGE_NAME="br-vpn-static"
|
||||||
|
TARGET_SUBNETS="10.3.1.0/24 10.255.255.0/24"
|
||||||
|
LAN_SUBNET="192.168.0.0/23"
|
||||||
|
LAN_INTERFACES="eth0 eth1 wlan0"
|
||||||
|
LOG_FILE="/var/log/cistech-routing.log"
|
||||||
|
|
||||||
|
log() {
|
||||||
|
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] [cistech-routing] $*"
|
||||||
|
echo "$msg" | tee -a "$LOG_FILE" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
get_lan_interface() {
|
||||||
|
ip route show default | awk '/default/ {for(i=1;i<=NF;i++) if($i=="dev") print $(i+1)}' | head -1
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_routes() {
|
||||||
|
log "Removing stale routes..."
|
||||||
|
for subnet in $TARGET_SUBNETS; do
|
||||||
|
ip route del "$subnet" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
log "Stale routes removed"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply_routes() {
|
||||||
|
local lan_if
|
||||||
|
lan_if="$(get_lan_interface)"
|
||||||
|
|
||||||
|
log "Applying host routing rules..."
|
||||||
|
log " Container IP: $CONTAINER_IP"
|
||||||
|
log " Bridge: $BRIDGE_NAME"
|
||||||
|
log " Target subnets: $TARGET_SUBNETS"
|
||||||
|
log " LAN interface: ${lan_if:-unknown}"
|
||||||
|
|
||||||
|
# Enable IP forwarding
|
||||||
|
echo 1 > /proc/sys/net/ipv4/ip_forward
|
||||||
|
log "IP forwarding enabled"
|
||||||
|
|
||||||
|
# Add routes to target subnets via container
|
||||||
|
for subnet in $TARGET_SUBNETS; do
|
||||||
|
ip route replace "$subnet" via "$CONTAINER_IP" dev "$BRIDGE_NAME"
|
||||||
|
log "Route added: $subnet via $CONTAINER_IP dev $BRIDGE_NAME"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Allow forwarding in DOCKER-USER chain for all LAN interfaces
|
||||||
|
for lan_if in $LAN_INTERFACES; do
|
||||||
|
if ip link show "$lan_if" &>/dev/null; then
|
||||||
|
# Allow traffic from LAN to container bridge
|
||||||
|
iptables -C DOCKER-USER -i "$lan_if" -o "$BRIDGE_NAME" -j ACCEPT 2>/dev/null || \
|
||||||
|
iptables -I DOCKER-USER 1 -i "$lan_if" -o "$BRIDGE_NAME" -j ACCEPT
|
||||||
|
|
||||||
|
# Allow return traffic
|
||||||
|
iptables -C DOCKER-USER -i "$BRIDGE_NAME" -o "$lan_if" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || \
|
||||||
|
iptables -I DOCKER-USER 1 -i "$BRIDGE_NAME" -o "$lan_if" -m state --state RELATED,ESTABLISHED -j ACCEPT
|
||||||
|
|
||||||
|
log "DOCKER-USER iptables rules added for $lan_if <-> $BRIDGE_NAME"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Masquerade traffic from LAN subnet to VPN bridge (using nft)
|
||||||
|
if ! nft list chain ip nat POSTROUTING 2>/dev/null | grep -q "saddr $LAN_SUBNET.*oifname.*$BRIDGE_NAME.*masquerade"; then
|
||||||
|
nft add rule ip nat POSTROUTING ip saddr "$LAN_SUBNET" oifname "$BRIDGE_NAME" counter masquerade
|
||||||
|
log "NAT masquerade rule added for $LAN_SUBNET -> $BRIDGE_NAME"
|
||||||
|
else
|
||||||
|
log "NAT masquerade rule already exists for $LAN_SUBNET -> $BRIDGE_NAME"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "OK: Host routing applied"
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_all() {
|
||||||
|
log "Removing all routing rules..."
|
||||||
|
|
||||||
|
# Remove routes
|
||||||
|
for subnet in $TARGET_SUBNETS; do
|
||||||
|
ip route del "$subnet" via "$CONTAINER_IP" dev "$BRIDGE_NAME" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
|
||||||
|
# Remove iptables rules for all LAN interfaces
|
||||||
|
for lan_if in $LAN_INTERFACES; do
|
||||||
|
iptables -D DOCKER-USER -i "$lan_if" -o "$BRIDGE_NAME" -j ACCEPT 2>/dev/null || true
|
||||||
|
iptables -D DOCKER-USER -i "$BRIDGE_NAME" -o "$lan_if" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || true
|
||||||
|
done
|
||||||
|
|
||||||
|
# Remove masquerade rule (using nft)
|
||||||
|
local handle
|
||||||
|
handle=$(nft -a list chain ip nat POSTROUTING 2>/dev/null | grep "saddr $LAN_SUBNET.*oifname.*$BRIDGE_NAME.*masquerade" | grep -oP 'handle \K\d+' | head -1)
|
||||||
|
if [ -n "$handle" ]; then
|
||||||
|
nft delete rule ip nat POSTROUTING handle "$handle" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "All routing rules removed"
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$ACTION" in
|
||||||
|
start)
|
||||||
|
remove_routes
|
||||||
|
apply_routes
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
remove_all
|
||||||
|
;;
|
||||||
|
restart)
|
||||||
|
remove_all
|
||||||
|
sleep 1
|
||||||
|
remove_routes
|
||||||
|
apply_routes
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $0 {start|stop|restart}" >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
68
apps/cistech-tunnel/shared/install-host-services.sh
Normal file
68
apps/cistech-tunnel/shared/install-host-services.sh
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Install host-side systemd services for cistech-tunnel
|
||||||
|
# Run this ONCE on the host after app install
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
APP_DATA_DIR="/etc/runtipi/app-data/runtipi/cistech-tunnel"
|
||||||
|
|
||||||
|
echo "Installing cistech-tunnel host services..."
|
||||||
|
|
||||||
|
# Create app-data directory for trigger file
|
||||||
|
sudo mkdir -p "$APP_DATA_DIR"
|
||||||
|
|
||||||
|
# Create the path unit (watches for trigger file)
|
||||||
|
sudo tee /etc/systemd/system/cistech-routing-watcher.path > /dev/null << EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Watch for cistech-tunnel routing trigger
|
||||||
|
|
||||||
|
[Path]
|
||||||
|
PathExists=$APP_DATA_DIR/restart-routing
|
||||||
|
Unit=cistech-routing-watcher.service
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Create the service unit (applies routes when triggered)
|
||||||
|
sudo tee /etc/systemd/system/cistech-routing-watcher.service > /dev/null << EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Apply cistech-tunnel routing rules
|
||||||
|
After=docker.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=$SCRIPT_DIR/host-routing.sh restart
|
||||||
|
ExecStartPost=/bin/rm -f $APP_DATA_DIR/restart-routing
|
||||||
|
ExecStartPost=/bin/bash -c 'echo "trigger cleared at \$(date)" >> $APP_DATA_DIR/watcher.log'
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Make host-routing.sh executable
|
||||||
|
chmod +x "$SCRIPT_DIR/host-routing.sh"
|
||||||
|
|
||||||
|
# Reload systemd and enable the watcher
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable cistech-routing-watcher.path
|
||||||
|
sudo systemctl start cistech-routing-watcher.path
|
||||||
|
|
||||||
|
# Disable the old boot-only service if it exists
|
||||||
|
if systemctl is-enabled cistech-routing.service &>/dev/null; then
|
||||||
|
echo "Disabling old cistech-routing.service (replaced by watcher)..."
|
||||||
|
sudo systemctl stop cistech-routing.service 2>/dev/null || true
|
||||||
|
sudo systemctl disable cistech-routing.service 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Apply routes now
|
||||||
|
echo "Applying initial routes..."
|
||||||
|
sudo "$SCRIPT_DIR/host-routing.sh" start
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Done! Watcher installed and routes applied."
|
||||||
|
echo ""
|
||||||
|
echo "To trigger route refresh from container:"
|
||||||
|
echo " touch /runtime/restart-routing"
|
||||||
|
echo ""
|
||||||
|
echo "To check watcher status:"
|
||||||
|
echo " systemctl status cistech-routing-watcher.path"
|
||||||
24
apps/cistech-tunnel/shared/uninstall-host-services.sh
Normal file
24
apps/cistech-tunnel/shared/uninstall-host-services.sh
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Uninstall host-side systemd services for cistech-tunnel
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "Removing cistech-tunnel host services..."
|
||||||
|
|
||||||
|
# Stop and disable the watcher
|
||||||
|
sudo systemctl stop cistech-routing-watcher.path 2>/dev/null || true
|
||||||
|
sudo systemctl disable cistech-routing-watcher.path 2>/dev/null || true
|
||||||
|
|
||||||
|
# Remove routing rules
|
||||||
|
/etc/runtipi/repos/runtipi/apps/cistech-tunnel/shared/host-routing.sh stop 2>/dev/null || true
|
||||||
|
|
||||||
|
# Remove systemd units
|
||||||
|
sudo rm -f /etc/systemd/system/cistech-routing-watcher.path
|
||||||
|
sudo rm -f /etc/systemd/system/cistech-routing-watcher.service
|
||||||
|
|
||||||
|
# Reload systemd
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Done! Host services removed."
|
||||||
@@ -160,6 +160,12 @@ setup_nat() {
|
|||||||
iptables -t nat -C POSTROUTING -o "$OC_INTERFACE" -j MASQUERADE 2>/dev/null || \
|
iptables -t nat -C POSTROUTING -o "$OC_INTERFACE" -j MASQUERADE 2>/dev/null || \
|
||||||
iptables -t nat -A POSTROUTING -o "$OC_INTERFACE" -j MASQUERADE
|
iptables -t nat -A POSTROUTING -o "$OC_INTERFACE" -j MASQUERADE
|
||||||
echo "NAT enabled on $OC_INTERFACE"
|
echo "NAT enabled on $OC_INTERFACE"
|
||||||
|
|
||||||
|
# Trigger host routing service
|
||||||
|
if [ -d /runtime ]; then
|
||||||
|
touch /runtime/restart-routing
|
||||||
|
echo "Host routing trigger sent"
|
||||||
|
fi
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
sleep 2
|
sleep 2
|
||||||
|
|||||||
Reference in New Issue
Block a user