Skip to content

Commit d75407f

Browse files
committed
feat(router): wip ipv6 only network
1 parent b337e62 commit d75407f

File tree

3 files changed

+184
-116
lines changed

3 files changed

+184
-116
lines changed

configurations/nixos/x86_64-linux/alnitak.nix

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -43,27 +43,27 @@
4343
args.auth-key = "file:/var/run/agenix/ts-google-9k";
4444
};
4545

46-
services.jae.router = {
47-
enable = true;
48-
useNextDns = true;
49-
nextDnsEnvFile = "/var/run/agenix/nextdns";
50-
restrictedMacs = [
51-
"5c:e0:c5:8a:24:6a"
52-
"b4:18:d1:ab:4e:5a"
53-
];
54-
upstreamDnsServers = [
55-
"2a07:a8c1::"
56-
"45.90.30.0"
57-
"2a07:a8c0::"
58-
"45.90.28.0"
59-
];
60-
externalInterface = "enp1s0";
61-
internalInterface = "enp2s0";
62-
internalInterfaceIP = "192.168.20.1";
63-
dnsMasqSettings.no-resolv = true;
64-
dnsMasqSettings.bogus-priv = true;
65-
dnsMasqSettings.strict-order = true;
66-
};
46+
# services.jae.router = {
47+
# enable = true;
48+
# useNextDns = true;
49+
# nextDnsEnvFile = "/var/run/agenix/nextdns";
50+
# restrictedMacs = [
51+
# "5c:e0:c5:8a:24:6a"
52+
# "b4:18:d1:ab:4e:5a"
53+
# ];
54+
# upstreamDnsServers = [
55+
# "2a07:a8c1::"
56+
# "45.90.30.0"
57+
# "2a07:a8c0::"
58+
# "45.90.28.0"
59+
# ];
60+
# externalInterface = "enp1s0";
61+
# internalInterface = "enp2s0";
62+
# internalInterfaceIP = "192.168.20.1";
63+
# dnsMasqSettings.no-resolv = true;
64+
# dnsMasqSettings.bogus-priv = true;
65+
# dnsMasqSettings.strict-order = true;
66+
# };
6767

6868
age.secrets = {
6969
ts-google-9k = {

configurations/nixos/x86_64-linux/sagittarius.nix

Lines changed: 98 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,56 @@
55
pkgs,
66
lib,
77
...
8-
}: {
8+
}:
9+
let
10+
# Detect public IPv4 from the WAN interface
11+
getPublicIpv4 = pkgs.writeShellScript "get-public-ipv4" ''
12+
${pkgs.iproute2}/bin/ip -4 -json addr show dev enp1s0f0 scope global | \
13+
${pkgs.jq}/bin/jq -r '.[0].addr_info[0].local // empty'
14+
'';
15+
16+
# Generate Jool NAT64 config with detected IP
17+
generateJoolConfig = pkgs.writeShellScript "generate-jool-config" ''
18+
PUBLIC_IP=$(${getPublicIpv4})
19+
20+
if [ -z "$PUBLIC_IP" ]; then
21+
echo "ERROR: Could not detect public IPv4 address on enp1s0f0" >&2
22+
exit 1
23+
fi
24+
25+
echo "Configuring Jool NAT64 with public IP: $PUBLIC_IP" >&2
26+
27+
# Generate the JSON config with the detected IP
28+
cat > /run/jool-nat64-default.conf <<EOF
29+
{
30+
"instance": "default",
31+
"framework": "netfilter",
32+
"global": {
33+
"pool6": "64:ff9b::/96",
34+
"manually-enabled": true
35+
},
36+
"pool4": [
37+
{
38+
"protocol": "TCP",
39+
"prefix": "$PUBLIC_IP/32",
40+
"port range": "10000-65535"
41+
},
42+
{
43+
"protocol": "UDP",
44+
"prefix": "$PUBLIC_IP/32",
45+
"port range": "10000-65535"
46+
},
47+
{
48+
"protocol": "ICMP",
49+
"prefix": "$PUBLIC_IP/32",
50+
"port range": "10000-65535"
51+
}
52+
]
53+
}
54+
EOF
55+
'';
56+
in
57+
{
958
publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINssAv/UibH5i9JxHFFWNNodKzmjYvPxx4mhTys3S1ZX";
1059

1160
bcachefs = {
@@ -82,33 +131,53 @@
82131

83132
services.jae.router = {
84133
enable = true;
85-
useNextDns = true;
86-
nextDnsEnvFile = "/var/run/agenix/nextdns";
87-
restrictedMacs = [
88-
"5c:e0:c5:8a:24:6a"
89-
"b4:18:d1:ab:4e:5a"
90-
];
91-
upstreamDnsServers = [
92-
"2a07:a8c1::"
93-
"45.90.30.0"
94-
"2a07:a8c0::"
95-
"45.90.28.0"
96-
];
134+
# restrictedMacs = [
135+
# "5c:e0:c5:8a:24:6a"
136+
# "b4:18:d1:ab:4e:5a"
137+
# ];
138+
# upstreamDnsServers = [
139+
# "2a07:a8c1::"
140+
# "45.90.30.0"
141+
# "2a07:a8c0::"
142+
# "45.90.28.0"
143+
# ];
97144
externalInterface = "enp1s0f0";
98145
internalInterface = "enp2s0";
99-
internalInterfaceIP = "192.168.20.1";
100-
dnsMasqSettings.no-resolv = true;
101-
dnsMasqSettings.bogus-priv = true;
102-
dnsMasqSettings.strict-order = true;
146+
# internalInterfaceIP = "192.168.20.1";
147+
# dnsMasqSettings.no-resolv = true;
148+
# dnsMasqSettings.bogus-priv = true;
149+
# dnsMasqSettings.strict-order = true;
103150
};
104151

105-
services.prometheus.exporters = {
106-
dnsmasq = {
107-
enable = true;
108-
dnsmasqListenAddress = "localhost:5342";
152+
## NAT64 configuration for IPv6-only clients to access IPv4 services
153+
## The public IPv4 address is automatically detected from enp1s0f0 at service start.
154+
## Note: While Jool is running, the router itself cannot access IPv4 services.
155+
## Workaround: Temporarily stop Jool when router needs IPv4 access:
156+
## systemctl stop jool-nat64-default.service
157+
## systemctl start jool-nat64-default.service
158+
networking.jool.enable = true;
159+
160+
systemd.services.jool-nat64-default = {
161+
after = ["network-online.target" "systemd-networkd.service"];
162+
wants = ["network-online.target"];
163+
164+
serviceConfig = {
165+
ExecStartPre = [
166+
"${pkgs.kmod}/bin/modprobe jool"
167+
generateJoolConfig
168+
];
169+
ExecStart = lib.mkForce "${pkgs.jool-cli}/bin/jool file handle /run/jool-nat64-default.conf";
170+
ExecStop = lib.mkForce "${pkgs.jool-cli}/bin/jool instance remove default";
109171
};
110172
};
111173

174+
# services.prometheus.exporters = {
175+
# dnsmasq = {
176+
# enable = true;
177+
# dnsmasqListenAddress = "localhost:5342";
178+
# };
179+
# };
180+
112181
services.vmagent = {
113182
prometheusConfig = let
114183
relabel_configs = [
@@ -120,14 +189,14 @@
120189
];
121190
in {
122191
scrape_configs = [
123-
{
124-
job_name = "dnsmasq";
125-
scrape_interval = "10s";
126-
static_configs = [
127-
{targets = ["127.0.0.1:9153"];}
128-
];
129-
inherit relabel_configs;
130-
}
192+
# {
193+
# job_name = "dnsmasq";
194+
# scrape_interval = "10s";
195+
# static_configs = [
196+
# {targets = ["127.0.0.1:9153"];}
197+
# ];
198+
# inherit relabel_configs;
199+
# }
131200
{
132201
job_name = "corerad";
133202
scrape_interval = "10s";

modules/router.nix

Lines changed: 65 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,14 @@
4242
in {
4343
options.services.jae.router = with lib.types; {
4444
enable = mkEnableOption "Whether to enable the router";
45-
#disableDns = mkEnableOption "Whether to disable dns server";
46-
useNextDns = mkEnableOption "Whether to use nextdns DoH for name resolution";
47-
nextDnsEnvFile = mkOption {
48-
type = nullOr str;
49-
example = "/path/to/envfile";
50-
default = null;
51-
};
5245
upstreamDnsServers = mkOption {
5346
type = listOf str;
5447
description = "List of upstream dns server addresses.";
5548
};
49+
# disableIPv4 = mkOption {
50+
# type = bool;
51+
# description = "If ipv4 should be disabled on the local network.";
52+
# };
5653
restrictedMacs = mkOption {
5754
type = listOf str;
5855
description = "List of mac addresses.";
@@ -115,33 +112,17 @@ in {
115112
internalInterfaces);
116113
};
117114

118-
networking.nat = {
119-
enable = true;
120-
inherit (cfg) externalInterface;
121-
internalInterfaces = internalInterfaceNames;
122-
};
115+
# networking.nat = {
116+
# enable = !cfg.disableIPv4;
117+
# inherit (cfg) externalInterface;
118+
# internalInterfaces = internalInterfaceNames;
119+
# };
123120

124121
environment.persistence."/keep".directories = ["/var/lib/dnsmasq"];
125122

126-
systemd.timers.kill-nextdns = {
127-
description = "Kill nextdns 5 minutes after boot. What a hack.";
128-
wantedBy = ["timers.target"];
129-
timerConfig.OnBootSec = "5m";
130-
};
131-
systemd.services.kill-nextdns = {
132-
description = "Kill nextdns 5 minutes after boot. What a hack.";
133-
after = ["network-online.target"];
134-
wants = ["network-online.target"];
135-
wantedBy = ["multi-user.target"];
136-
serviceConfig = {
137-
Type = "oneshot";
138-
ExecStartPre = "/run/current-system/sw/bin/pkill -9 nextdns";
139-
ExecStart = "/run/current-system/sw/bin/systemctl restart nextdns";
140-
};
141-
};
123+
## NAT64 (Jool) should be configured per-host in the host configuration
124+
## See configurations/nixos/x86_64-linux/sagittarius.nix for example
142125

143-
## enable jool nat64
144-
networking.jool.enable = true;
145126
## enable ipv6 on local network
146127
services.corerad = {
147128
enable = true;
@@ -151,15 +132,6 @@ in {
151132
prometheus = true;
152133
};
153134
interfaces = [
154-
{
155-
name = "pref64";
156-
advertise = true;
157-
prefix = [
158-
{
159-
prefix = "64:ff9b::/96";
160-
}
161-
];
162-
}
163135
{
164136
name = cfg.internalInterface;
165137
advertise = true;
@@ -179,36 +151,63 @@ in {
179151
};
180152
};
181153

182-
services.dnsmasq.enable = true;
183-
services.dnsmasq.resolveLocalQueries = true;
184-
services.dnsmasq.settings =
185-
{
186-
dhcp-range = mapAttrsToList (tag: net: "${tag},${net.base}.10,${net.base}.128,255.255.255.0,24h") internalInterfaces;
187-
dhcp-option = (mapAttrsToList (tag: net: "${tag},option:router,${net.address}") internalInterfaces) ++ ["option:dns-server,${cfg.internalInterfaceIP}"];
188-
interface = internalInterfaceNames;
189-
}
190-
// {
191-
server = mkIf (!cfg.useNextDns) cfg.upstreamDnsServers;
192-
# server = mkMerge [
193-
# (mkIf (!cfg.useNextDns) cfg.upstreamDnsServers)
194-
# (mkIf cfg.useNextDns ["127.0.0.1#5555"])
195-
# ];
196-
dhcp-authoritative = true;
197-
dhcp-leasefile = "/var/lib/dnsmasq/dnsmasq.leases";
198-
add-mac = "text";
199-
add-subnet = "32,128";
200-
port = 5342;
201-
}
202-
// cfg.dnsMasqSettings;
154+
# . {
155+
# bind ::
156+
# dns64 64:ff9b::/96
157+
# forward . tls://2606:4700:4700::1111 {
158+
# tls_servername 1dot1dot1dot1.cloudflare-dns.com
159+
# }
160+
# cache 30
161+
# log
162+
# errors
163+
# }
203164

204-
services.resolved.enable = false;
205-
services.nextdns.enable = cfg.useNextDns;
206-
services.nextdns.arguments = (flatten (map (mac: ["-profile" "${mac}=\${KIDSDNS_ID}"]) cfg.restrictedMacs)) ++ ["-profile" "${cfg.internalInterfaceIP}/24=\${NEXTDNS_ID}" "-cache-size" "10MB" "-discovery-dns" "127.0.0.1:5342" "-report-client-info" "-listen" "${cfg.internalInterfaceIP}:53" "-listen" "127.0.0.1:53"];
207-
systemd.services.nextdns = mkIf cfg.useNextDns {
208-
serviceConfig.EnvironmentFile = cfg.nextDnsEnvFile;
209-
after = ["systemd-networkd-wait-online.service"];
165+
services.coredns = {
166+
enable = true;
167+
config = ''
168+
. {
169+
bind ::
170+
dns64 64:ff9b::/96
171+
forward . tls://2606:4700:4700::1111 {
172+
tls_servername 1dot1dot1dot1.cloudflare-dns.com
173+
}
174+
cache 300
175+
log
176+
}
177+
'';
210178
};
211179

180+
# services.dnsmasq.enable = true;
181+
# services.dnsmasq.resolveLocalQueries = true;
182+
# services.dnsmasq.settings =
183+
# {
184+
# dhcp-range = lib.mkIf (!cfg.disableIPv4) mapAttrsToList (tag: net: "${tag},${net.base}.10,${net.base}.128,255.255.255.0,24h") internalInterfaces;
185+
# dhcp-option = lib.mkIf (!cfg.disableIPv4) (mapAttrsToList (tag: net: "${tag},option:router,${net.address}") internalInterfaces) ++ ["option:dns-server,${cfg.internalInterfaceIP}"];
186+
# interface = internalInterfaceNames;
187+
# except-interface = cfg.externalInterface;
188+
# }
189+
# // {
190+
# server = mkIf (!cfg.useNextDns) cfg.upstreamDnsServers;
191+
# # server = mkMerge [
192+
# # (mkIf (!cfg.useNextDns) cfg.upstreamDnsServers)
193+
# # (mkIf cfg.useNextDns ["127.0.0.1#5555"])
194+
# # ];
195+
# dhcp-authoritative = true;
196+
# dhcp-leasefile = "/var/lib/dnsmasq/dnsmasq.leases";
197+
# add-mac = "text";
198+
# add-subnet = "32,128";
199+
# port = 5342;
200+
# }
201+
# // cfg.dnsMasqSettings;
202+
203+
services.resolved.enable = false;
204+
# services.nextdns.enable = cfg.useNextDns;
205+
# services.nextdns.arguments = (flatten (map (mac: ["-profile" "${mac}=\${KIDSDNS_ID}"]) cfg.restrictedMacs)) ++ ["-profile" "${cfg.internalInterfaceIP}/24=\${NEXTDNS_ID}" "-cache-size" "10MB" "-discovery-dns" "127.0.0.1:5342" "-report-client-info" "-listen" "${cfg.internalInterfaceIP}:53" "-listen" "127.0.0.1:53"];
206+
# systemd.services.nextdns = mkIf cfg.useNextDns {
207+
# serviceConfig.EnvironmentFile = cfg.nextDnsEnvFile;
208+
# after = ["systemd-networkd-wait-online.service"];
209+
# };
210+
212211
boot.kernel.sysctl."net.ipv4.conf.all.forwarding" = true;
213212
boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = true;
214213

0 commit comments

Comments
 (0)