summaryrefslogtreecommitdiff
path: root/hosts
diff options
context:
space:
mode:
Diffstat (limited to 'hosts')
-rw-r--r--hosts/sif/default.nix7
-rw-r--r--hosts/surtr/bifrost/default.nix6
-rw-r--r--hosts/surtr/default.nix26
-rw-r--r--hosts/surtr/dns/zones/li.yggdrasil.soa5
-rw-r--r--hosts/surtr/http/webdav/default.nix8
-rw-r--r--hosts/surtr/http/webdav/py-webdav/setup.py2
-rw-r--r--hosts/surtr/vpn/default.nix177
-rw-r--r--hosts/surtr/vpn/geri.pub1
-rw-r--r--hosts/surtr/vpn/ruleset.nft189
-rw-r--r--hosts/surtr/vpn/surtr.priv26
-rw-r--r--hosts/surtr/vpn/surtr.pub1
-rw-r--r--hosts/vidhar/network/bifrost/default.nix6
12 files changed, 424 insertions, 30 deletions
diff --git a/hosts/sif/default.nix b/hosts/sif/default.nix
index 257743fd..f51535ea 100644
--- a/hosts/sif/default.nix
+++ b/hosts/sif/default.nix
@@ -140,12 +140,6 @@ in {
140 ''; 140 '';
141 }; 141 };
142 142
143 environment.etc."systemd/networkd.conf" = {
144 text = ''
145 [Network]
146 RouteTable=wgrz:1025
147 '';
148 };
149 systemd.network = { 143 systemd.network = {
150 netdevs = { 144 netdevs = {
151 wgrz = { 145 wgrz = {
@@ -234,6 +228,7 @@ in {
234 }; 228 };
235 }; 229 };
236 }; 230 };
231 config.routeTables.wgrz = 1025;
237 }; 232 };
238 sops.secrets.wgrz = { 233 sops.secrets.wgrz = {
239 format = "binary"; 234 format = "binary";
diff --git a/hosts/surtr/bifrost/default.nix b/hosts/surtr/bifrost/default.nix
index 8f1e602d..790af94a 100644
--- a/hosts/surtr/bifrost/default.nix
+++ b/hosts/surtr/bifrost/default.nix
@@ -56,11 +56,5 @@ in {
56 owner = "root"; 56 owner = "root";
57 group = "systemd-network"; 57 group = "systemd-network";
58 }; 58 };
59 environment.etc."systemd/networkd.conf" = {
60 text = ''
61 [Network]
62 RouteTable=bifrost:1026
63 '';
64 };
65 }; 59 };
66} 60}
diff --git a/hosts/surtr/default.nix b/hosts/surtr/default.nix
index 87dd27b0..2be25560 100644
--- a/hosts/surtr/default.nix
+++ b/hosts/surtr/default.nix
@@ -2,7 +2,7 @@
2{ 2{
3 imports = with flake.nixosModules.systemProfiles; [ 3 imports = with flake.nixosModules.systemProfiles; [
4 qemu-guest openssh rebuild-machines zfs 4 qemu-guest openssh rebuild-machines zfs
5 ./zfs.nix ./dns ./tls ./http ./bifrost ./matrix ./postgresql.nix ./prometheus ./email 5 ./zfs.nix ./dns ./tls ./http ./bifrost ./matrix ./postgresql.nix ./prometheus ./email ./vpn
6 ]; 6 ];
7 7
8 config = { 8 config = {
@@ -57,6 +57,7 @@
57 { address = "202.61.241.61"; prefixLength = 22; } 57 { address = "202.61.241.61"; prefixLength = 22; }
58 ]; 58 ];
59 ipv6.addresses = [ 59 ipv6.addresses = [
60 { address = "2a03:4000:52:ada:98e7:16ff:feba:7a2e"; prefixLength = 128; }
60 { address = "2a03:4000:52:ada::"; prefixLength = 96; } 61 { address = "2a03:4000:52:ada::"; prefixLength = 96; }
61 ]; 62 ];
62 }; 63 };
@@ -68,11 +69,15 @@
68 }; 69 };
69 }; 70 };
70 71
71 systemd.network.networks."40-ens3".networkConfig = { 72 systemd.network = {
72 Domains = lib.mkForce "~."; 73 networks = {
73 DNS = [ "127.0.0.1:5353" "[::1]:5353" ]; 74 "40-ens3".networkConfig = {
74 # DNSSEC = true; 75 Domains = lib.mkForce "~.";
75 # DNS = [ "46.38.225.230" "46.38.252.230" "2a03:4000:0:1::e1e6" "2a03:4000:8000::fce6" ]; 76 DNS = [ "127.0.0.1:5353" "[::1]:5353" ];
77 # DNSSEC = true;
78 # DNS = [ "46.38.225.230" "46.38.252.230" "2a03:4000:0:1::e1e6" "2a03:4000:8000::fce6" ];
79 };
80 };
76 }; 81 };
77 82
78 services.resolved = { 83 services.resolved = {
@@ -85,8 +90,13 @@
85 proxies = { 90 proxies = {
86 ens3 = { 91 ens3 = {
87 router = false; 92 router = false;
88 rules."2a03:4000:52:ada::/64" = { 93 rules = {
89 method = "static"; 94 "2a03:4000:20:259::/64" = {
95 method = "static";
96 };
97 "2a03:4000:52:ada::/64" = {
98 method = "static";
99 };
90 }; 100 };
91 }; 101 };
92 }; 102 };
diff --git a/hosts/surtr/dns/zones/li.yggdrasil.soa b/hosts/surtr/dns/zones/li.yggdrasil.soa
index 889e78b2..1a4e4656 100644
--- a/hosts/surtr/dns/zones/li.yggdrasil.soa
+++ b/hosts/surtr/dns/zones/li.yggdrasil.soa
@@ -1,7 +1,7 @@
1$ORIGIN yggdrasil.li. 1$ORIGIN yggdrasil.li.
2$TTL 3600 2$TTL 3600
3@ IN SOA ns.yggdrasil.li. root.yggdrasil.li. ( 3@ IN SOA ns.yggdrasil.li. root.yggdrasil.li. (
4 2022050505 ; serial 4 2022072800 ; serial
5 10800 ; refresh 5 10800 ; refresh
6 3600 ; retry 6 3600 ; retry
7 604800 ; expire 7 604800 ; expire
@@ -43,6 +43,9 @@ surtr IN AAAA 2a03:4000:52:ada::
43surtr IN MX 0 surtr.yggdrasil.li 43surtr IN MX 0 surtr.yggdrasil.li
44surtr IN TXT "v=spf1 a:surtr.yggdrasil.li -all" 44surtr IN TXT "v=spf1 a:surtr.yggdrasil.li -all"
45 45
46vpn IN A 185.243.10.86
47vpn IN AAAA 2a03:4000:20:259::
48
46surtr._domainkey.surtr IN CNAME surtr._domainkey.yggdrasil.li. 49surtr._domainkey.surtr IN CNAME surtr._domainkey.yggdrasil.li.
47_dmarc.surtr IN TXT "v=DMARC1;p=reject;sp=reject;pct=100;adkim=s;aspf=s;rua=mailto:postmaster@yggdrasil.li;ruf=mailto:postmaster@yggdrasil.li" 50_dmarc.surtr IN TXT "v=DMARC1;p=reject;sp=reject;pct=100;adkim=s;aspf=s;rua=mailto:postmaster@yggdrasil.li;ruf=mailto:postmaster@yggdrasil.li"
48 51
diff --git a/hosts/surtr/http/webdav/default.nix b/hosts/surtr/http/webdav/default.nix
index f0aec1e9..5f2955bc 100644
--- a/hosts/surtr/http/webdav/default.nix
+++ b/hosts/surtr/http/webdav/default.nix
@@ -1,4 +1,7 @@
1{ config, libs, pkgs, flakeInputs, ... }: 1{ config, lib, pkgs, flakeInputs, ... }:
2
3with lib;
4
2let 5let
3 webdavSocket = config.services.uwsgi.runDir + "/webdav.sock"; 6 webdavSocket = config.services.uwsgi.runDir + "/webdav.sock";
4 7
@@ -10,9 +13,10 @@ let
10 python = "python3"; 13 python = "python3";
11 requirements = '' 14 requirements = ''
12 PyNaCl ==1.5.* 15 PyNaCl ==1.5.*
13 psycopg ==3.0.*
14 WsgiDAV ==4.0.* 16 WsgiDAV ==4.0.*
15 ''; 17 '';
18 # psycopg >=3.0.15,<3.1
19 # _.psycopg.patches = [];
16 }; 20 };
17in { 21in {
18 config = { 22 config = {
diff --git a/hosts/surtr/http/webdav/py-webdav/setup.py b/hosts/surtr/http/webdav/py-webdav/setup.py
index dbe345c1..d59c2548 100644
--- a/hosts/surtr/http/webdav/py-webdav/setup.py
+++ b/hosts/surtr/http/webdav/py-webdav/setup.py
@@ -11,7 +11,7 @@ setuptools.setup(
11 python_requires=">=3.8", 11 python_requires=">=3.8",
12 install_requires=[ 12 install_requires=[
13 "PyNaCl ==1.5.*", 13 "PyNaCl ==1.5.*",
14 "psycopg ==3.0.*", 14 # "psycopg ==3.0.*",
15 "WsgiDAV ==4.0.*", 15 "WsgiDAV ==4.0.*",
16 ], 16 ],
17) 17)
diff --git a/hosts/surtr/vpn/default.nix b/hosts/surtr/vpn/default.nix
new file mode 100644
index 00000000..4f334105
--- /dev/null
+++ b/hosts/surtr/vpn/default.nix
@@ -0,0 +1,177 @@
1{ pkgs, config, lib, ... }:
2
3with lib;
4
5let
6 trim = str: if hasSuffix "\n" str then trim (removeSuffix "\n" str) else str;
7 prefix4 = "10.84.47";
8 prefix6 = "2a03:4000:52:ada:5";
9in {
10 config = {
11 boot.kernel.sysctl = {
12 "net.netfilter.nf_log_all_netns" = true;
13 };
14
15 networking.namespaces = {
16 enable = true;
17 containers."vpn".config = {
18 boot.kernel.sysctl = {
19 "net.core.rmem_max" = "4194304";
20 "net.core.wmem_max" = "4194304";
21 };
22
23 environment = {
24 noXlibs = true;
25 systemPackages = with pkgs; [ wireguard-tools ];
26 };
27
28 networking = {
29 useDHCP = false;
30 useNetworkd = true;
31 useHostResolvConf = false;
32 firewall.enable = false;
33 nftables = {
34 enable = true;
35 rulesetFile = ./ruleset.nft;
36 };
37 };
38
39 services.resolved.fallbackDns = [
40 "9.9.9.9#dns.quad9.net"
41 "149.112.112.112#dns.quad9.net"
42 "2620:fe::fe#dns.quad9.net"
43 "2620:fe::9#dns.quad9.net"
44 ];
45
46 systemd.tmpfiles.rules = [
47 "d /etc/wireguard 0755 root systemd-network - -"
48 "C /etc/wireguard/surtr.priv 0640 root systemd-network - /run/host/credentials/surtr.priv"
49 ];
50
51 systemd.network = {
52 netdevs = {
53 vpn = {
54 netdevConfig = {
55 Name = "vpn";
56 Kind = "wireguard";
57 };
58 wireguardConfig = {
59 PrivateKeyFile = "/etc/wireguard/surtr.priv";
60 ListenPort = 51820;
61 };
62 wireguardPeers = [
63 { wireguardPeerConfig = {
64 AllowedIPs = ["${prefix6}:1::/96" "${prefix4}.1/32"];
65 PublicKey = trim (readFile ./geri.pub);
66 };
67 }
68 ];
69 };
70 };
71
72 networks = {
73 upstream = {
74 name = "upstream";
75 matchConfig = {
76 Name = "upstream";
77 };
78 linkConfig = {
79 RequiredForOnline = true;
80 };
81 networkConfig = {
82 Address = [ "185.243.10.86/32" "2a03:4000:20:259::/64" ];
83 LLMNR = false;
84 MulticastDNS = false;
85 };
86 routes = [
87 { routeConfig = {
88 Destination = "202.61.240.0/22";
89 };
90 }
91 { routeConfig = {
92 Destination = "0.0.0.0/0";
93 Gateway = "202.61.240.1";
94 };
95 }
96 { routeConfig = {
97 Destination = "::/0";
98 Gateway = "fe80::1";
99 };
100 }
101 ];
102 extraConfig = ''
103 [Neighbor]
104 Address=202.61.240.1
105 LinkLayerAddress=00:00:5e:00:01:01
106 '';
107 };
108 vpn = {
109 name = "vpn";
110 matchConfig = {
111 Name = "vpn";
112 };
113 address = ["${prefix6}::/96" "${prefix4}.0/32"];
114 routes = [
115 { routeConfig = {
116 Destination = "${prefix6}::/80";
117 };
118 }
119 { routeConfig = {
120 Destination = "${prefix4}.0/24";
121 };
122 }
123 ];
124 linkConfig = {
125 RequiredForOnline = false;
126 };
127 networkConfig = {
128 LLMNR = false;
129 MulticastDNS = false;
130 };
131 };
132 };
133 };
134 };
135 };
136
137 systemd.services = {
138 "vpn-upstream" = {
139 bindsTo = ["netns@vpn.service"];
140 after = ["netns@vpn.service"];
141 serviceConfig = {
142 Type = "oneshot";
143 RemainAfterExit = true;
144 ExecStop = "${pkgs.iproute}/bin/ip netns exec vpn ip link delete upstream";
145 };
146 path = with pkgs; [ iproute procps ];
147 script = ''
148 ip netns exec vpn sysctl \
149 net.ipv6.conf.all.forwarding=1 \
150 net.ipv6.conf.default.forwarding=1 \
151 net.ipv4.conf.all.forwarding=1 \
152 net.ipv4.conf.default.forwarding=1
153
154 ip link add link ens3 name upstream type ipvlan mode l2
155 ip link set upstream netns vpn
156 '';
157 };
158
159 "netns-container@vpn" = {
160 wantedBy = ["multi-user.target" "network-online.target"];
161 after = ["vpn-upstream.service"];
162 bindsTo = ["vpn-upstream.service"];
163
164 serviceConfig = {
165 LoadCredential = [
166 "surtr.priv:${config.sops.secrets.vpn.path}"
167 ];
168 };
169 };
170 };
171
172 sops.secrets.vpn = {
173 format = "binary";
174 sopsFile = ./surtr.priv;
175 };
176 };
177}
diff --git a/hosts/surtr/vpn/geri.pub b/hosts/surtr/vpn/geri.pub
new file mode 100644
index 00000000..ed5de2b2
--- /dev/null
+++ b/hosts/surtr/vpn/geri.pub
@@ -0,0 +1 @@
sYuQSNZHzfegv8HRz71jnZm2nFLGeRnaGwVonhKUj2k=
diff --git a/hosts/surtr/vpn/ruleset.nft b/hosts/surtr/vpn/ruleset.nft
new file mode 100644
index 00000000..3cdb7a8a
--- /dev/null
+++ b/hosts/surtr/vpn/ruleset.nft
@@ -0,0 +1,189 @@
1define icmp_protos = {ipv6-icmp, icmp, igmp}
2
3table arp filter {
4 limit lim_arp {
5 rate over 50 mbytes/second burst 50 mbytes
6 }
7
8 counter arp-rx {}
9 counter arp-tx {}
10
11 counter arp-ratelimit-rx {}
12 counter arp-ratelimit-tx {}
13
14 chain input {
15 type filter hook input priority filter
16 policy accept
17
18 limit name lim_arp counter name arp-ratelimit-rx drop
19
20 counter name arp-rx
21 }
22
23 chain output {
24 type filter hook output priority filter
25 policy accept
26
27 limit name lim_arp counter name arp-ratelimit-tx drop
28
29 counter name arp-tx
30 }
31}
32
33table inet filter {
34 limit lim_reject {
35 rate over 1000/second burst 1000 packets
36 }
37
38 limit lim_icmp {
39 rate over 50 mbytes/second burst 50 mbytes
40 }
41
42 counter invalid-fw {}
43 counter fw-lo {}
44 counter fw-vpn {}
45 counter fw-upstream {}
46
47 counter icmp-ratelimit-upstream-fw {}
48 counter icmp-ratelimit-vpn-fw {}
49 counter icmp-ratelimit-established-fw {}
50
51 counter icmp-upstream-fw {}
52 counter icmp-vpn-fw {}
53 counter icmp-established-fw {}
54
55 counter reject-ratelimit-fw {}
56 counter reject-fw {}
57 counter reject-tcp-fw {}
58 counter reject-icmp-fw {}
59
60 counter drop-fw {}
61
62 counter invalid-rx {}
63
64 counter rx-lo {}
65 counter invalid-local4-rx {}
66 counter invalid-local6-rx {}
67
68 counter icmp-ratelimit-rx {}
69 counter icmp-rx {}
70
71 counter wg-rx {}
72
73 counter established-rx {}
74
75 counter reject-ratelimit-rx {}
76 counter reject-rx {}
77 counter reject-tcp-rx {}
78 counter reject-icmp-rx {}
79
80 counter drop-rx {}
81
82 counter tx-lo {}
83
84 counter icmp-ratelimit-tx {}
85 counter icmp-tx {}
86
87 counter wg-tx {}
88
89 counter tx {}
90
91 chain forward {
92 type filter hook forward priority filter
93 policy drop
94
95
96 ct state invalid log level debug prefix "vpn: drop invalid forward: " counter name invalid-fw drop
97
98
99 iifname lo counter name fw-lo accept
100
101 meta l4proto $icmp_protos iifname upstream limit name lim_icmp counter name icmp-ratelimit-upstream-fw drop
102 meta l4proto $icmp_protos iifname upstream counter name icmp-upstream-fw accept
103 meta l4proto $icmp_protos iifname vpn limit name lim_icmp counter name icmp-ratelimit-vpn-fw drop
104 meta l4proto $icmp_protos iifname vpn counter name icmp-vpn-fw accept
105 meta l4proto $icmp_protos ct state {established, related} limit name lim_icmp counter name icmp-ratelimit-established-fw drop
106 meta l4proto $icmp_protos ct state {established, related} counter name icmp-established-fw accept
107
108
109 iifname upstream oifname vpn ct state {established, related} counter name fw-vpn accept
110 iifname vpn oifname upstream counter name fw-upstream accept
111
112
113 limit name lim_reject log level debug prefix "vpn: drop forward: " counter name reject-ratelimit-fw drop
114 log level debug prefix "vpn: reject forward: " counter name reject-fw
115 meta l4proto tcp ct state new counter name reject-tcp-fw reject with tcp reset
116 ct state new counter name reject-icmp-fw reject
117
118
119 counter name drop-fw
120 }
121
122 chain input {
123 type filter hook input priority filter
124 policy drop
125
126
127 ct state invalid log level debug prefix "vpn: drop invalid input: " counter name invalid-rx drop
128
129
130 iifname lo counter name rx-lo accept
131 iif != lo ip daddr 127.0.0.1/8 counter name invalid-local4-rx reject
132 iif != lo ip6 daddr ::1/128 counter name invalid-local6-rx reject
133
134 meta l4proto $icmp_protos limit name lim_icmp counter name icmp-ratelimit-rx drop
135 meta l4proto $icmp_protos counter name icmp-rx accept
136
137 udp dport 51820 counter name wg-rx accept
138
139 ct state {established, related} counter name established-rx accept
140
141
142 limit name lim_reject log level debug prefix "vpn: drop input: " counter name reject-ratelimit-rx drop
143 log level debug prefix "vpn: reject input: " counter name reject-rx
144 meta l4proto tcp ct state new counter name reject-tcp-rx reject with tcp reset
145 ct state new counter name reject-icmp-rx reject
146
147
148 counter name drop-rx
149 }
150
151 chain output {
152 type filter hook output priority filter
153 policy accept
154
155
156 oifname lo counter name tx-lo accept
157
158 meta l4proto $icmp_protos limit name lim_icmp counter name icmp-ratelimit-tx drop
159 meta l4proto $icmp_protos counter name icmp-tx accept
160
161
162 udp sport 51820 counter name wg-tx
163
164
165 counter name tx
166 }
167}
168
169table inet nat {
170 counter nat {}
171
172 chain postrouting {
173 type nat hook postrouting priority srcnat
174 policy accept
175
176 iifname vpn counter name nat masquerade
177 }
178}
179
180table ip mss_clamp {
181 counter mss-clamp {}
182
183 chain postrouting {
184 type filter hook postrouting priority mangle
185 policy accept
186
187 iifname vpn oifname upstream tcp flags & (syn|rst) == syn counter name mss-clamp tcp option maxseg size set rt mtu
188 }
189} \ No newline at end of file
diff --git a/hosts/surtr/vpn/surtr.priv b/hosts/surtr/vpn/surtr.priv
new file mode 100644
index 00000000..707287f5
--- /dev/null
+++ b/hosts/surtr/vpn/surtr.priv
@@ -0,0 +1,26 @@
1{
2 "data": "ENC[AES256_GCM,data:dhGFzsKjzYTfFwxrcCGTVPKQoy12RDLfIqdBcxO7/aib90w/yfTWBQP2zNRa,iv:71HbOJRbpzLxYWztxzvM/qJNLdJQckaZVDOIAl5UKjI=,tag:JjF2zr78zjI7RPXqQaHmyg==,type:str]",
3 "sops": {
4 "kms": null,
5 "gcp_kms": null,
6 "azure_kv": null,
7 "hc_vault": null,
8 "age": null,
9 "lastmodified": "2022-07-28T19:09:57Z",
10 "mac": "ENC[AES256_GCM,data:Q2179Mp3h/FXVzM1T5sRfci+mo/gCGfUm5824GBTbCzwIsTMjSpPz/wByg0WQJ/WB3wnns+VfCh+epqnKcP73KKUmNysGNJ9DH1hNukmTWMZEI309yLE/GgDs76xGyt9hXdHClq30qhKT17bXQ7Pq08c437vfSwSCcKoKOcr6Ls=,iv:u81NRHwKSKb7Nfz2gC1tjdYlfrFETjF/gEMGAha4Y7g=,tag:zdxYtbiKtY46MGP/nO8S5w==,type:str]",
11 "pgp": [
12 {
13 "created_at": "2022-07-28T19:09:57Z",
14 "enc": "-----BEGIN PGP MESSAGE-----\n\nhF4DXxoViZlp6dISAQdAa7ohlS2wGvuH11I4GvYZQmKbQVZUcwpV1XX6YMvLQV0w\n8fMshflTFWUnmHAR5ERg6ZpESFiAXAlkUMTLIZBhDTAN92jCu7+nnNFK1QgBVE07\n0lwBilABJT++m953o6ic4h/9yeyx5Wc6+XxS3d1Mc4qgNBzX/TBVEoKmuUgkHwET\nd0nftLYbKmICgCBgDgllWJLSOU4XSksmYIeMwiSpyNzv8oKz8u73SZz20rJ9kQ==\n=phWI\n-----END PGP MESSAGE-----\n",
15 "fp": "30D3453B8CD02FE2A3E7C78C0FB536FB87AE8F51"
16 },
17 {
18 "created_at": "2022-07-28T19:09:57Z",
19 "enc": "-----BEGIN PGP MESSAGE-----\n\nhF4DyFKFNkTVG5oSAQdAV4pW8CJP/QP0S/w5e7S/Xrox+Ix/NBvw2N2fWp+5FwAw\nATp3d/QGyk+vwuQpQj3zq/cEzrWrrq19Gl+UUjSyI2rkpUnxWboA2xICYVkb91Oz\n0lwBLu54X/3X5Nd2krPv+Qa7AWPBKF6BkE2PIjjrvPgyJ4/XiFzawJsILH37QPqs\n7PcrteF15UNR416omVNZoWpF3Tq/j4Jw+ewRhU9WjOXe2GO8/X9zjTD9fRrpIQ==\n=YtV+\n-----END PGP MESSAGE-----\n",
20 "fp": "7ED22F4AA7BB55728B643DC5471B7D88E4EF66F8"
21 }
22 ],
23 "unencrypted_suffix": "_unencrypted",
24 "version": "3.7.3"
25 }
26} \ No newline at end of file
diff --git a/hosts/surtr/vpn/surtr.pub b/hosts/surtr/vpn/surtr.pub
new file mode 100644
index 00000000..48edc8fc
--- /dev/null
+++ b/hosts/surtr/vpn/surtr.pub
@@ -0,0 +1 @@
99nWsdE/KJHfOZjmG5suUQSfIj6UBuxS5+zOL+ynYmU=
diff --git a/hosts/vidhar/network/bifrost/default.nix b/hosts/vidhar/network/bifrost/default.nix
index ec78e6d9..752e3e3c 100644
--- a/hosts/vidhar/network/bifrost/default.nix
+++ b/hosts/vidhar/network/bifrost/default.nix
@@ -72,11 +72,5 @@ in {
72 owner = "root"; 72 owner = "root";
73 group = "systemd-network"; 73 group = "systemd-network";
74 }; 74 };
75 environment.etc."systemd/networkd.conf" = {
76 text = ''
77 [Network]
78 RouteTable=bifrost:1026
79 '';
80 };
81 }; 75 };
82} 76}