From 91f83a5b8a951aaeef3cf67f51b0d729e3fc21c9 Mon Sep 17 00:00:00 2001 From: shum Date: Thu, 22 Oct 2026 05:34:51 +0000 Subject: [PATCH] scripts: pass IPv6 neighbour discovery in egress --- apps/simplex-store-service/README.md | 3 ++- scripts/store-service/egress.sh | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/simplex-store-service/README.md b/apps/simplex-store-service/README.md index d704b01365..772f02e028 100644 --- a/apps/simplex-store-service/README.md +++ b/apps/simplex-store-service/README.md @@ -349,7 +349,8 @@ host's own addresses, public ones included, since a rebinding name can answer wi reach whatever listens on the host. The exceptions are the endpoints the service is configured to use, on their ports: the RPC node (`[chain] rpc_url`), BTCPay (`[btcpay] host`), the database and the DNS resolvers in `/etc/resolv.conf`. Replies on -connections already open, such as Caddy's requests, pass. +connections already open, such as Caddy's requests, pass, and so does IPv6 neighbour discovery on +the link. `egress.sh` writes this as the chain `STORE_SERVICE_EGRESS` in `iptables` and `ip6tables`, and rebuilds it on every run. With compose's host networking it matches the service's user in diff --git a/scripts/store-service/egress.sh b/scripts/store-service/egress.sh index d7ae809efe..b43eb4eed1 100755 --- a/scripts/store-service/egress.sh +++ b/scripts/store-service/egress.sh @@ -18,6 +18,10 @@ DOCKER_CHAIN=DOCKER-USER # apps/simplex-store-service/src/StoreService/Names/Profiles.hs). DENIED_V4=(0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16 172.16.0.0/12 192.168.0.0/16 198.18.0.0/15 224.0.0.0/4 240.0.0.0/4) DENIED_V6=(fc00::/7 fe80::/10 fec0::/10 ff00::/8) +# Conntrack leaves neighbour discovery untracked, and RFC 4861 sends it with hop limit 255, which a +# routed packet cannot keep, so these pass only on the link. +NEIGHBOUR_DISCOVERY=(router-solicitation neighbour-solicitation neighbour-advertisement) +NEIGHBOUR_DISCOVERY_HOP_LIMIT=255 # IPv4-compatible, IPv4-mapped and NAT64 addresses carry an IPv4 address in their last 32 bits. V4_EMBEDDING_PREFIXES=(:: ::ffff: 64:ff9b::) @@ -233,8 +237,13 @@ v4_in_v6() { # One rule per line, in chain order: replies, then the allowed endpoints, then the denied ranges. # A rebinding name can also answer with one of the host's own public addresses, so those are denied too. rules_for() { - local family=$1 entry address address_family proto port range prefix + local family=$1 entry address address_family proto port range prefix type echo "-m conntrack --ctstate ESTABLISHED,RELATED -j RETURN" + if [[ $family == 6 ]]; then + for type in "${NEIGHBOUR_DISCOVERY[@]}"; do + echo "-p ipv6-icmp --icmpv6-type $type -m hl --hl-eq $NEIGHBOUR_DISCOVERY_HOP_LIMIT -j RETURN" + done + fi for entry in "${allowed[@]}"; do read -r address proto port <<<"$entry" if [[ $address == *:* ]]; then address_family=6; else address_family=4; fi