Initial resurrection kit — 81 scripts, 62 references, configs, systemd units, crons, Docker compose files, Caddy config, master README
This commit is contained in:
Executable
+237
@@ -0,0 +1,237 @@
|
||||
#!/bin/bash
|
||||
# wisp-vpn.sh — Connect/disconnect L2TP/IPsec VPN to MicroTik gateway
|
||||
# Usage: wisp-vpn.sh [up|down|status]
|
||||
|
||||
CONFIG_DIR="$(dirname "$0")"
|
||||
YAML="$CONFIG_DIR/config.yaml"
|
||||
|
||||
# Parse YAML values
|
||||
get_cfg() {
|
||||
local key="$1"
|
||||
grep -A50 "^vpn:" "$YAML" | grep "^ $key:" | sed 's/.*: //' | tr -d '"' | sed 's/ *#.*//' | head -1
|
||||
}
|
||||
|
||||
SERVER_IP=$(get_cfg server_ip)
|
||||
PSK=$(get_cfg psk)
|
||||
USERNAME=$(get_cfg username)
|
||||
PASSWORD=$(get_cfg password)
|
||||
IFACE=$(get_cfg interface)
|
||||
IFACE="${IFACE:-ppp0}"
|
||||
|
||||
L2TP_NAME="wisp-vpn"
|
||||
IPSEC_CONF="/etc/ipsec.conf"
|
||||
IPSEC_SECRETS="/etc/ipsec.secrets"
|
||||
XL2TPD_CONF="/etc/xl2tpd/xl2tpd.conf"
|
||||
L2TP_PEERS="/etc/ppp/peers/$L2TP_NAME"
|
||||
L2TP_SECRETS="/etc/ppp/chap-secrets"
|
||||
|
||||
case "$1" in
|
||||
up)
|
||||
echo "[*] Bringing up L2TP/IPsec VPN to $SERVER_IP ..."
|
||||
|
||||
# Write ipsec.conf for strongSwan compatibility
|
||||
cat > "$IPSEC_CONF" <<IPSEOF
|
||||
config setup
|
||||
charondebug="all"
|
||||
uniqueids=yes
|
||||
conn $L2TP_NAME
|
||||
auto=add
|
||||
keyexchange=ikev1
|
||||
authby=secret
|
||||
type=transport
|
||||
left=%defaultroute
|
||||
leftprotoport=17/1701
|
||||
right=$SERVER_IP
|
||||
rightprotoport=17/1701
|
||||
ike=aes128-sha1-modp1024
|
||||
esp=aes128-sha1-modp1024
|
||||
dpddelay=30
|
||||
dpdtimeout=120
|
||||
dpdaction=clear
|
||||
keyingtries=%forever
|
||||
ikelifetime=24h
|
||||
lifetime=8h
|
||||
margin=10m
|
||||
IPSEOF
|
||||
|
||||
# Write ipsec.secrets — specify exact IPs for strongSwan
|
||||
printf '5.161.114.8 %s : PSK "%s"\n' "$SERVER_IP" "$PSK" > "$IPSEC_SECRETS"
|
||||
|
||||
# Write xl2tpd.conf
|
||||
cat > "$XL2TPD_CONF" <<XL2EOF
|
||||
[global]
|
||||
port = 1701
|
||||
[lac $L2TP_NAME]
|
||||
lns = $SERVER_IP
|
||||
ppp debug = yes
|
||||
pppoptfile = /etc/ppp/options.$L2TP_NAME
|
||||
length bit = yes
|
||||
require pap = no
|
||||
require chap = yes
|
||||
autodial = yes
|
||||
redial = yes
|
||||
redial timeout = 5
|
||||
max redials = 3
|
||||
XL2EOF
|
||||
|
||||
# Write ppp options — NO replacedefaultroute (keeps internet on eth0)
|
||||
# Also: no defaultroute at all — we'll add the necessary routes manually
|
||||
# after the connection is established to avoid ppp0 recursion.
|
||||
cat > "/etc/ppp/options.$L2TP_NAME" <<PPPOEOF
|
||||
ipcp-accept-local
|
||||
ipcp-accept-remote
|
||||
refuse-eap
|
||||
noccp
|
||||
noauth
|
||||
idle 0
|
||||
maxfail 3
|
||||
debug
|
||||
name $USERNAME
|
||||
password $PASSWORD
|
||||
mtu 1400
|
||||
mru 1400
|
||||
usepeerdns
|
||||
lcp-echo-interval 10
|
||||
lcp-echo-failure 5
|
||||
PPPOEOF
|
||||
|
||||
# Write or update chap-secrets entry
|
||||
if grep -q "^\"$USERNAME\"" "$L2TP_SECRETS" 2>/dev/null; then
|
||||
# Entry exists — remove old line and add new one (password may have changed)
|
||||
sed -i "/^\"$USERNAME\"/d" "$L2TP_SECRETS" 2>/dev/null
|
||||
fi
|
||||
echo "\"$USERNAME\" * \"$PASSWORD\" *" >> "$L2TP_SECRETS"
|
||||
|
||||
# Ensure the L2TP server IP has a clean route through eth0 BEFORE ipsec starts
|
||||
# This prevents IPsec + pppd from creating a routing loop (ppp0 recursion)
|
||||
CURRENT_GW=$(ip route get 8.8.8.8 | awk '{print $3}' | head -1)
|
||||
if [ -n "$CURRENT_GW" ]; then
|
||||
ip route add "$SERVER_IP" via "$CURRENT_GW" dev eth0 metric 100 2>/dev/null || \
|
||||
ip route change "$SERVER_IP" via "$CURRENT_GW" dev eth0 metric 100 2>/dev/null
|
||||
echo "[route] $SERVER_IP via $CURRENT_GW (avoids ppp0 recursion)"
|
||||
fi
|
||||
|
||||
# Reload config — loads new connections added to ipsec.conf
|
||||
ipsec reload 2>/dev/null
|
||||
sleep 2
|
||||
ipsec up $L2TP_NAME 2>/dev/null
|
||||
sleep 3
|
||||
|
||||
systemctl restart xl2tpd 2>/dev/null
|
||||
sleep 3
|
||||
|
||||
# Trigger the connection
|
||||
echo "c $L2TP_NAME" > /var/run/xl2tpd/l2tp-control 2>/dev/null
|
||||
sleep 5
|
||||
|
||||
# Verify
|
||||
if ip addr show "$IFACE" 2>/dev/null | grep -q "inet "; then
|
||||
LOCAL_IP=$(ip addr show "$IFACE" | grep "inet " | awk '{print $2}')
|
||||
echo "[+] VPN connected! Interface: $IFACE, IP: $LOCAL_IP"
|
||||
|
||||
# Add route to peer's LAN subnet through ppp0 (if the peer address is known)
|
||||
# Without this, ppp0 recursion happens when pppd applies defaultroute
|
||||
PEER_IP=$(echo "$LOCAL_IP" | cut -d' ' -f1)
|
||||
echo "[*] Adding route to VPN peer's subnet via $IFACE ..."
|
||||
ip route add 192.168.88.0/24 dev "$IFACE" 2>/dev/null && \
|
||||
echo " [route] Added 192.168.88.0/24 via $IFACE" || \
|
||||
echo " [route] 192.168.88.0/24 already exists"
|
||||
|
||||
# Add static routes for routed tower subnets from config
|
||||
echo "[*] Adding static routes for tower subnets ..."
|
||||
ROUTES=$(grep -A50 "^vpn:" "$YAML" | grep -A50 "^ routes:" | grep "^- " | sed 's/.*- //' | tr -d '"')
|
||||
if [ -n "$ROUTES" ]; then
|
||||
echo "$ROUTES" | while read -r subnet; do
|
||||
if [ -n "$subnet" ]; then
|
||||
# Check if route already exists
|
||||
if ip route show "$subnet" 2>/dev/null | grep -q .; then
|
||||
echo " [route] $subnet already exists"
|
||||
else
|
||||
ip route add "$subnet" dev "$IFACE"
|
||||
echo " [route] Added $subnet via $IFACE"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo " (no routes configured in config.yaml)"
|
||||
fi
|
||||
|
||||
# Safety: verify internet connectivity still works
|
||||
# If ppp's replacedefaultroute kills internet, kill ppp immediately
|
||||
echo "[*] Checking internet connectivity ..."
|
||||
if ping -c 1 -W 3 8.8.8.8 >/dev/null 2>&1 || ping -c 1 -W 3 1.1.1.1 >/dev/null 2>&1; then
|
||||
echo "[+] Internet reachable — VPN is safe"
|
||||
else
|
||||
echo "[-] INTERNET LOST after VPN connect!"
|
||||
echo " Tearing down VPN to restore connectivity ..."
|
||||
echo "d $L2TP_NAME" > /var/run/xl2tpd/l2tp-control 2>/dev/null
|
||||
pkill -f "pppd.*$L2TP_NAME" 2>/dev/null
|
||||
ipsec down $L2TP_NAME 2>/dev/null
|
||||
sleep 2
|
||||
echo "[-] VPN terminated — internet should be restored"
|
||||
exit 1
|
||||
fi
|
||||
exit 0
|
||||
else
|
||||
echo "[-] VPN connection failed (ppp0 not up)."
|
||||
echo " Cleaning up IPsec to avoid orphaned tunnel ..."
|
||||
echo "d $L2TP_NAME" > /var/run/xl2tpd/l2tp-control 2>/dev/null
|
||||
pkill -f "pppd.*$L2TP_NAME" 2>/dev/null
|
||||
ipsec down $L2TP_NAME 2>/dev/null
|
||||
sleep 2
|
||||
echo " Check logs: journalctl -u xl2tpd -n 20"
|
||||
echo " ipsec status"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
down)
|
||||
echo "[*] Tearing down VPN ..."
|
||||
|
||||
# Remove static routes for tower subnets
|
||||
ROUTES=$(grep -A50 "^vpn:" "$YAML" | grep -A50 "^ routes:" | grep "^- " | sed 's/.*- //' | tr -d '"')
|
||||
if [ -n "$ROUTES" ]; then
|
||||
echo "[*] Removing static routes ..."
|
||||
echo "$ROUTES" | while read -r subnet; do
|
||||
if [ -n "$subnet" ]; then
|
||||
ip route del "$subnet" dev "$IFACE" 2>/dev/null && \
|
||||
echo " [route] Removed $subnet" || true
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
echo "d $L2TP_NAME" > /var/run/xl2tpd/l2tp-control 2>/dev/null
|
||||
ipsec down $L2TP_NAME 2>/dev/null
|
||||
sleep 2
|
||||
# Kill the ppp interface
|
||||
pkill -f "pppd.*$L2TP_NAME" 2>/dev/null
|
||||
sleep 1
|
||||
# Safety: ensure default route via eth0 is restored
|
||||
DEFAULT_GW=$(ip route show default | grep eth0 | head -1 || true)
|
||||
if [ -z "$DEFAULT_GW" ]; then
|
||||
GW=$(ip route get 8.8.8.8 | awk '{print $3}' | head -1)
|
||||
DEV=$(ip route get 8.8.8.8 | awk '{print $5}' | head -1)
|
||||
if [ -n "$GW" ] && [ -n "$DEV" ]; then
|
||||
echo " [safety] Default route lost — restoring via $DEV"
|
||||
ip route add default via "$GW" dev "$DEV" metric 100 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
echo "[+] VPN disconnected"
|
||||
;;
|
||||
|
||||
status)
|
||||
if ip addr show "$IFACE" 2>/dev/null | grep -q "inet "; then
|
||||
LOCAL_IP=$(ip addr show "$IFACE" | grep "inet " | awk '{print $2}')
|
||||
echo "[+] VPN is UP — $IFACE: $LOCAL_IP"
|
||||
exit 0
|
||||
else
|
||||
echo "[-] VPN is DOWN"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Usage: $0 {up|down|status}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user