This repository has no description
0

Configure Feed

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

superconfig / configs / container-bridge.nix
5.8 kB 199 lines
1{ config, pkgs, ... }: 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 = [ 10 "fd00:c700::1" 11 "127.0.0.1" 12 ]; 13 access-control = [ 14 "fd00:c700::/64 allow" 15 "127.0.0.0/8 allow" 16 ]; 17 # DNS64: synthesize AAAA with NAT64 prefix 18 module-config = ''"dns64 validator iterator"''; 19 dns64-prefix = "64:ff9b::/96"; 20 # Always synthesize, even if real AAAA exists (needed when host has no IPv6) 21 dns64-synthall = "yes"; 22 # Handle reverse DNS for NAT64 prefix locally (return NXDOMAIN immediately) 23 # Without this, PTR lookups for 64:ff9b::* timeout waiting for upstream 24 local-zone = ''"0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.b.9.f.f.4.6.0.0.ip6.arpa." static''; 25 }; 26 forward-zone = [ 27 { 28 name = "."; 29 forward-addr = [ 30 "1.1.1.1" # Cloudflare (IPv4 - always works) 31 "8.8.8.8" # Google (IPv4) 32 "2606:4700:4700::1111" # Cloudflare (IPv6 - when available) 33 ]; 34 } 35 ]; 36 }; 37 }; 38 39 # Bridge interface for containers 40 systemd.network.netdevs."10-ctr0" = { 41 netdevConfig = { 42 Kind = "bridge"; 43 Name = "ctr0"; 44 }; 45 }; 46 47 systemd.network.networks."10-ctr0" = { 48 matchConfig.Name = "ctr0"; 49 address = [ "fd00:c700::1/64" ]; 50 networkConfig = { 51 ConfigureWithoutCarrier = true; 52 IPv6SendRA = true; # Enable Router Advertisements 53 }; 54 55 # Router Advertisement configuration 56 ipv6SendRAConfig = { 57 Managed = false; # No DHCPv6 for addresses (use SLAAC) 58 OtherInformation = false; # No DHCPv6 for DNS (use RDNSS) 59 RouterLifetimeSec = 1800; 60 DNS = [ "fd00:c700::1" ]; # RDNSS: advertise DNS64 resolver 61 }; 62 ipv6Prefixes = [ 63 { Prefix = "fd00:c700::/64"; } 64 ]; 65 # Advertise NAT64 prefix via PREF64 option (RFC 8781) 66 ipv6PREF64Prefixes = [ 67 { Prefix = "64:ff9b::/96"; } 68 ]; 69 }; 70 71 # Exclude from NetworkManager 72 networking.networkmanager.unmanaged = [ "ctr0" ]; 73 74 # IP forwarding 75 boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = 1; 76 boot.kernel.sysctl."net.ipv4.ip_forward" = 1; 77 78 # Jool NAT64 kernel module 79 boot.extraModulePackages = [ config.boot.kernelPackages.jool ]; 80 boot.kernelModules = [ "jool" ]; 81 82 systemd.services.jool = { 83 description = "Jool NAT64"; 84 after = [ "network.target" ]; 85 wantedBy = [ "multi-user.target" ]; 86 serviceConfig = { 87 Type = "oneshot"; 88 RemainAfterExit = true; 89 # Use --iptables mode so we can control which packets Jool processes 90 # (--netfilter mode intercepts ALL traffic to pool6, breaking upstream NAT64) 91 ExecStart = "${pkgs.jool-cli}/bin/jool instance add --iptables --pool6 64:ff9b::/96"; 92 ExecStop = "${pkgs.jool-cli}/bin/jool instance remove"; 93 }; 94 }; 95 96 # Update Jool pool4 with current IPv4 address (needed for NAT64 on dynamic IPs) 97 systemd.services.jool-pool4-update = { 98 description = "Update Jool NAT64 pool4 with current IPv4"; 99 after = [ 100 "jool.service" 101 "network-online.target" 102 ]; 103 wants = [ "network-online.target" ]; 104 wantedBy = [ "multi-user.target" ]; 105 path = [ 106 pkgs.iproute2 107 pkgs.gawk 108 pkgs.jool-cli 109 ]; 110 serviceConfig = { 111 Type = "oneshot"; 112 RemainAfterExit = true; 113 }; 114 script = '' 115 # Get default route's source IP 116 IP=$(ip -4 route get 1.1.1.1 2>/dev/null | awk '/src/ {print $7}') 117 if [ -n "$IP" ]; then 118 # Flush old pool and add new 119 jool pool4 flush --tcp 2>/dev/null || true 120 jool pool4 flush --udp 2>/dev/null || true 121 jool pool4 flush --icmp 2>/dev/null || true 122 jool pool4 add "$IP" 1-65535 --tcp 123 jool pool4 add "$IP" 1-65535 --udp 124 jool pool4 add "$IP" 1-65535 --icmp 125 echo "Jool pool4 updated to $IP" 126 else 127 echo "No IPv4 address found, skipping pool4 update" 128 fi 129 ''; 130 }; 131 132 # Firewall rules for container bridge 133 krebs.iptables.tables.filter.FORWARD.rules = [ 134 # IPv6 forwarding for containers 135 { 136 v4 = false; 137 v6 = true; 138 predicate = "-i ctr0"; 139 target = "ACCEPT"; 140 } 141 { 142 v4 = false; 143 v6 = true; 144 predicate = "-o ctr0 -m conntrack --ctstate RELATED,ESTABLISHED"; 145 target = "ACCEPT"; 146 } 147 # IPv4 forwarding for NAT64 translated packets 148 { 149 v4 = true; 150 v6 = false; 151 predicate = "-m conntrack --ctstate RELATED,ESTABLISHED"; 152 target = "ACCEPT"; 153 } 154 { 155 v4 = true; 156 v6 = false; 157 predicate = ""; 158 target = "ACCEPT"; 159 } 160 ]; 161 162 # NAT66 - masquerade container IPv6 to reach public IPv6 (when host has IPv6) 163 # Note: No IPv4 MASQUERADE needed - jool does SNAT with pool4 address for NAT64 traffic 164 krebs.iptables.tables.nat.POSTROUTING.rules = [ 165 { 166 v4 = false; 167 v6 = true; 168 predicate = "-s fd00:c700::/64 ! -d fd00:c700::/64"; 169 target = "MASQUERADE"; 170 } 171 ]; 172 173 # Allow containers to reach host's DNS64 resolver (IPv6 only) 174 krebs.iptables.tables.filter.INPUT.rules = [ 175 { 176 v4 = false; 177 v6 = true; 178 predicate = "-s fd00:c700::/64 -p udp --dport 53"; 179 target = "ACCEPT"; 180 } 181 { 182 v4 = false; 183 v6 = true; 184 predicate = "-s fd00:c700::/64 -p tcp --dport 53"; 185 target = "ACCEPT"; 186 } 187 ]; 188 189 # Send only container traffic to Jool NAT64 (--iptables mode) 190 # Host traffic to 64:ff9b::/96 passes through to upstream NAT64 (e.g., Android hotspot) 191 krebs.iptables.tables.mangle.PREROUTING.rules = [ 192 { 193 v4 = false; 194 v6 = true; 195 predicate = "-i ctr0 -d 64:ff9b::/96"; 196 target = "JOOL"; 197 } 198 ]; 199}