BIND laeuft auf pinix und beantwortet 0ff.space autoritativ, ohne Rekursion, ohne Zonenuebertragung und ohne dynamische Updates. Die Delegation bleibt unveraendert bei Cloudflare; diese Stufe aendert an der oeffentlichen Aufloesung nichts. `networking.resolvconf.useLocalResolver = false` ist zwingend: das BIND-Modul setzt sonst localhost als Resolver, und pinix' Uplink ist IPv6-only ueber Mangos DNS64 -- ein autoritativer Server ohne Rekursion kann den nicht ersetzen. Nach dem switch geprueft, resolv.conf und ausgehende Aufloesung sind unveraendert. Dazu die dynamische Nachfuehrung der oeffentlichen IPv6: mango-dns aktualisiert per Timer ausschliesslich den bestehenden AAAA von ipv6-test.0ff.space bei Cloudflare, ueber das schon vorhandene verschluesselte Token. Die Zonendatei ist dagegen ein Snapshot und wird noch nicht nachgefuehrt -- vor einer Delegation zu loesen, zusammen mit Glue, Redundanz und RFC2136 fuer ACME. Die Mango-DNAT-Regel fuer Port 53 ist als Skript abgelegt, aber noch nicht angewandt; BIND ist bislang nur im LAN und im Tailnet erreichbar. Web- und SSH-Weiterleitungen tragen jetzt die Form ohne src_dip und ueberleben damit einen Praefixwechsel. Aktiviert auf pinix als 074z8vkzdldf98hvnsyacws21cbbrpkr-nixos-system-pinix. Details und Pruefungen: docs/pinix-bind.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Aw4viUJyXGP8ANocHiF15q
109 lines
4.3 KiB
Bash
Executable file
109 lines
4.3 KiB
Bash
Executable file
#!/bin/sh
|
|
# Persistente IPv6-Weiterleitung auf dem Mango (GL.iNet, OpenWrt/fw4).
|
|
#
|
|
# Aufruf von einem Host im LAN des Mango:
|
|
# ssh root@192.168.8.1 'sh -s' < scripts/configure-mango-ipv6-web.sh
|
|
#
|
|
# Parameter als Umgebungsvariablen, alle mit Vorgabewert -- ein anderes
|
|
# Ziel braucht keine Aenderung an diesem Skript:
|
|
# ssh root@192.168.8.1 "TARGET_IP='fdee:...:1234' sh -s" < scripts/...
|
|
#
|
|
# TARGET_IP LAN-Adresse, die die Weiterleitung bekommt.
|
|
# Vorgabe: pinix (hosts/pinix/localServices/traefik.nix).
|
|
# PUBLIC_IP Optional: Eingang auf genau diese Adresse beschraenken.
|
|
# Vorgabe: alle Adressen der WAN6-Zone, damit ein neues
|
|
# Mobilfunkpraefix ohne Firewall-Aenderung funktioniert.
|
|
# WAN_DEV WAN-Interface. Vorgabe usb0 (Nokia-Tethering).
|
|
# PORT_MAP aussen:innen, leerzeichengetrennt. Vorgabe leitet 8080 auf
|
|
# 80 um, weil auf dem Ziel nur Traefik mit 80/443 lauscht --
|
|
# der alte 8080-Link bleibt so gueltig und landet ueber die
|
|
# HTTPS-Weiterleitung des Proxys richtig.
|
|
# RULE_PREFIX Namenspraefix der erzeugten uci-Sektionen.
|
|
# STALE_PREFIXES Praefixe frueherer Ziele, die entfernt werden.
|
|
#
|
|
# Es gibt bewusst keine SNAT-Rueckwegregeln mehr. Die frueheren
|
|
# tnix_web_return_* waren noetig, weil tnix seine Default-Route auf dem
|
|
# iPhone-Hotspot behielt und Antwortpakete sonst am Mango vorbeiliefen.
|
|
# pinix' Default-Route zeigt ohnehin auf den Mango. Ohne SNAT steht die
|
|
# echte Client-Adresse im Traefik-Log statt der Router-Adresse.
|
|
#
|
|
# Bestehende, nicht zugehoerige Firewall-Einstellungen bleiben unberuehrt.
|
|
# Kein Netzwerk-Neustart, nur ein Firewall-Reload.
|
|
set -eu
|
|
|
|
TARGET_IP="${TARGET_IP:-fdee:3c40:44f0:0:dea6:32ff:fe48:c6c8}"
|
|
WAN_DEV="${WAN_DEV:-usb0}"
|
|
PORT_MAP="${PORT_MAP:-80:80 443:443 8080:80}"
|
|
RULE_PREFIX="${RULE_PREFIX:-pinix_web}"
|
|
STALE_PREFIXES="${STALE_PREFIXES:-tnix_web}"
|
|
|
|
echo "Weiterleitung: [${PUBLIC_IP:-WAN6}] -> [$TARGET_IP] ($PORT_MAP)"
|
|
|
|
[ "$(uci -q get firewall.@zone[1].name)" = wan ]
|
|
[ "$(uci -q get firewall.wan6.name)" = wan6 ]
|
|
[ -z "$(uci changes firewall)" ] || {
|
|
echo 'Unsaved firewall changes exist; refusing to overwrite them.' >&2
|
|
exit 1
|
|
}
|
|
backup_dir=$(mktemp -d /root/ipv6-web-firewall-backup.XXXXXX)
|
|
cp /etc/config/firewall "$backup_dir/firewall"
|
|
echo "Firewall backup: $backup_dir/firewall"
|
|
trap 'uci revert firewall' EXIT
|
|
|
|
# GL.iNet creates wan6 separately but leaves wan matching both families.
|
|
# Restrict wan to IPv4 so IPv6 can reach its own zone, including after reload.
|
|
uci set 'firewall.@zone[1].family=ipv4'
|
|
uci set firewall.wan6.masq_src='fdee:3c40:44f0::/48'
|
|
uci set firewall.ipv6_lan_wan=forwarding
|
|
uci set firewall.ipv6_lan_wan.src=lan
|
|
uci set firewall.ipv6_lan_wan.dest=wan6
|
|
uci set firewall.ipv6_lan_wan.family=ipv6
|
|
|
|
# Preserve the existing WAN IPv6 control-traffic policy in the correct zone.
|
|
for index in 2 3 4 5; do
|
|
[ "$(uci -q get "firewall.@rule[$index].family")" = ipv6 ]
|
|
uci set "firewall.@rule[$index].src=wan6"
|
|
# Remove only named copies created by the initial migration attempt.
|
|
uci -q delete "firewall.ipv6_control_$index" || true
|
|
done
|
|
|
|
# Alte Weiterleitungen samt ihrer SNAT-Rueckwege entfernen, bevor die neuen
|
|
# entstehen: zwei DNAT-Regeln auf dieselbe Adresse und denselben Port waeren
|
|
# ein Wettlauf um den ersten Treffer.
|
|
for prefix in $STALE_PREFIXES "$RULE_PREFIX"; do
|
|
for section in $(uci show firewall \
|
|
| sed -n "s/^firewall\.\($prefix[A-Za-z0-9_]*\)=.*/\1/p" | sort -u); do
|
|
echo " entferne alte Regel firewall.$section"
|
|
uci -q delete "firewall.$section" || true
|
|
done
|
|
done
|
|
|
|
for mapping in $PORT_MAP; do
|
|
outer="${mapping%%:*}"
|
|
inner="${mapping##*:}"
|
|
rule="firewall.${RULE_PREFIX}_$outer"
|
|
uci set "$rule=redirect"
|
|
uci set "$rule.name=IPv6 web $outer -> $inner"
|
|
uci set "$rule.family=ipv6"
|
|
uci set "$rule.src=wan6"
|
|
if [ -n "${PUBLIC_IP:-}" ]; then
|
|
uci set "$rule.src_dip=$PUBLIC_IP"
|
|
fi
|
|
uci set "$rule.src_dport=$outer"
|
|
uci set "$rule.dest=lan"
|
|
uci set "$rule.dest_ip=$TARGET_IP"
|
|
uci set "$rule.dest_port=$inner"
|
|
uci set "$rule.proto=tcp"
|
|
uci set "$rule.target=DNAT"
|
|
uci set "$rule.reflection=0"
|
|
done
|
|
|
|
if ! fw4 check; then
|
|
uci revert firewall
|
|
echo 'Firewall validation failed; staged changes reverted.' >&2
|
|
exit 1
|
|
fi
|
|
uci commit firewall
|
|
trap - EXIT
|
|
/etc/init.d/firewall reload
|
|
echo 'Persistent IPv6 web forwarding installed.'
|