This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

container-bridge: fix NAT64 with DNS64 and dynamic pool4

- Add dns64-synthall to synthesize NAT64 addresses even for sites with AAAA
- Add jool-pool4-update service to configure pool4 with host's current IPv4
- Enable IPv4 forwarding for NAT64 translated packets
- Add IPv4 FORWARD and MASQUERADE rules for NAT64 traffic
- Fix krebs.iptables rules to use explicit v4/v6 flags
- Update virtulus container to use fd00:c700:: prefix and local DNS64

+92 -12
+81 -4
2configs/container-bridge.nix
··· 1 1 { config, lib, pkgs, ... }: 2 2 { 3 + # Local DNS64 resolver for containers 4 + # Synthesizes AAAA records with 64:ff9b::/96 prefix for IPv4-only hosts 5 + services.unbound = { 6 + enable = true; 7 + settings = { 8 + server = { 9 + interface = [ "fd00:c700::1" "127.0.0.1" ]; 10 + access-control = [ 11 + "fd00:c700::/64 allow" 12 + "127.0.0.0/8 allow" 13 + ]; 14 + # DNS64: synthesize AAAA with NAT64 prefix 15 + module-config = ''"dns64 validator iterator"''; 16 + dns64-prefix = "64:ff9b::/96"; 17 + # Always synthesize, even if real AAAA exists (needed when host has no IPv6) 18 + dns64-synthall = "yes"; 19 + }; 20 + forward-zone = [ 21 + { 22 + name = "."; 23 + forward-addr = [ 24 + "1.1.1.1" # Cloudflare (IPv4 - always works) 25 + "8.8.8.8" # Google (IPv4) 26 + "2606:4700:4700::1111" # Cloudflare (IPv6 - when available) 27 + ]; 28 + } 29 + ]; 30 + }; 31 + }; 32 + 3 33 # Bridge interface for containers 4 34 systemd.network.netdevs."10-ctr0" = { 5 35 netdevConfig = { ··· 10 40 11 41 systemd.network.networks."10-ctr0" = { 12 42 matchConfig.Name = "ctr0"; 13 - address = [ "fd00:ctr::1/64" ]; 43 + address = [ "fd00:c700::1/64" ]; 14 44 networkConfig.ConfigureWithoutCarrier = true; 15 45 }; 16 46 17 47 # Exclude from NetworkManager 18 48 networking.networkmanager.unmanaged = [ "ctr0" ]; 19 49 20 - # IPv6 forwarding 50 + # IP forwarding 21 51 boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = 1; 52 + boot.kernel.sysctl."net.ipv4.ip_forward" = 1; 22 53 23 54 # Jool NAT64 kernel module 24 55 boot.extraModulePackages = [ config.boot.kernelPackages.jool ]; ··· 36 67 }; 37 68 }; 38 69 70 + # Update Jool pool4 with current IPv4 address (needed for NAT64 on dynamic IPs) 71 + systemd.services.jool-pool4-update = { 72 + description = "Update Jool NAT64 pool4 with current IPv4"; 73 + after = [ "jool.service" "network-online.target" ]; 74 + wants = [ "network-online.target" ]; 75 + wantedBy = [ "multi-user.target" ]; 76 + path = [ pkgs.iproute2 pkgs.gawk pkgs.jool-cli ]; 77 + serviceConfig = { 78 + Type = "oneshot"; 79 + RemainAfterExit = true; 80 + }; 81 + script = '' 82 + # Get default route's source IP 83 + IP=$(ip -4 route get 1.1.1.1 2>/dev/null | awk '/src/ {print $7}') 84 + if [ -n "$IP" ]; then 85 + # Flush old pool and add new 86 + jool pool4 flush --tcp 2>/dev/null || true 87 + jool pool4 flush --udp 2>/dev/null || true 88 + jool pool4 flush --icmp 2>/dev/null || true 89 + jool pool4 add "$IP" 1-65535 --tcp 90 + jool pool4 add "$IP" 1-65535 --udp 91 + jool pool4 add "$IP" 1-65535 --icmp 92 + echo "Jool pool4 updated to $IP" 93 + else 94 + echo "No IPv4 address found, skipping pool4 update" 95 + fi 96 + ''; 97 + }; 98 + 39 99 # Firewall rules for container bridge 40 100 krebs.iptables.tables.filter.FORWARD.rules = [ 41 - { v6 = true; predicate = "-i ctr0"; target = "ACCEPT"; } 42 - { v6 = true; predicate = "-o ctr0 -m conntrack --ctstate RELATED,ESTABLISHED"; target = "ACCEPT"; } 101 + # IPv6 forwarding for containers 102 + { v4 = false; v6 = true; predicate = "-i ctr0"; target = "ACCEPT"; } 103 + { v4 = false; v6 = true; predicate = "-o ctr0 -m conntrack --ctstate RELATED,ESTABLISHED"; target = "ACCEPT"; } 104 + # IPv4 forwarding for NAT64 translated packets 105 + { v4 = true; v6 = false; predicate = "-m conntrack --ctstate RELATED,ESTABLISHED"; target = "ACCEPT"; } 106 + { v4 = true; v6 = false; predicate = ""; target = "ACCEPT"; } 107 + ]; 108 + 109 + # NAT66 - masquerade container IPv6 to reach public IPv6 (when host has IPv6) 110 + # NAT44 - masquerade NAT64 translated IPv4 packets 111 + krebs.iptables.tables.nat.POSTROUTING.rules = [ 112 + { v4 = false; v6 = true; predicate = "-s fd00:c700::/64 ! -d fd00:c700::/64"; target = "MASQUERADE"; } 113 + { v4 = true; v6 = false; predicate = ""; target = "MASQUERADE"; } # Masquerade all outbound IPv4 114 + ]; 115 + 116 + # Allow containers to reach host's DNS64 resolver (IPv6 only) 117 + krebs.iptables.tables.filter.INPUT.rules = [ 118 + { v4 = false; v6 = true; predicate = "-s fd00:c700::/64 -p udp --dport 53"; target = "ACCEPT"; } 119 + { v4 = false; v6 = true; predicate = "-s fd00:c700::/64 -p tcp --dport 53"; target = "ACCEPT"; } 43 120 ]; 44 121 }
+11 -8
machines/virtulus/container.nix
··· 15 15 16 16 machineName = "virtulus"; 17 17 ipv6Suffix = formatIPv6Suffix (ipv6SuffixFun machineName); 18 + ipv6Address = "fd00:c700::${ipv6Suffix}"; 18 19 in 19 20 { 20 21 privateNetwork = true; 21 22 hostBridge = "ctr0"; 22 - 23 - # Static IPv6 from hostname hash: fd00:ctr::7371:bba8:ddd5:45e4 24 - localAddress6 = "fd00:ctr::${ipv6Suffix}/64"; 25 23 26 24 specialArgs = { inherit self; }; 27 25 ··· 33 31 clan.core.settings.directory = self; 34 32 clan.core.settings.machine.name = machineName; 35 33 36 - # DNS64 resolvers (Cloudflare) 37 - networking.nameservers = [ 38 - "2606:4700:4700::64" 39 - "2606:4700:4700::6400" 40 - ]; 34 + # Configure IPv6 inside the container (on eth0 interface) 35 + systemd.network.networks."10-container" = { 36 + matchConfig.Name = "eth0"; 37 + address = [ "${ipv6Address}/64" ]; 38 + gateway = [ "fd00:c700::1" ]; 39 + networkConfig.ConfigureWithoutCarrier = true; 40 + }; 41 + 42 + # Use host's local DNS64 resolver 43 + networking.nameservers = [ "fd00:c700::1" ]; 41 44 }; 42 45 }