Compare commits

..

1 Commits

Author SHA1 Message Date
ca5b0c2d6c yggdrasil: peer with pantoto.net over ipv6 2022-01-14 01:03:54 +01:00
92 changed files with 20002 additions and 5483 deletions

View File

@ -78,10 +78,6 @@ ausgeführt.
### LXC-Containers auf Server ### LXC-Containers auf Server
Warum Container? Mehrere Routing-Tabellen verteile auf virtuelle
Router statt Policy Routing oder Virtual Routing Functions. Container
sind einfach zwischen Servern migrierbar.
Ein Server erwartet die für ihn (`location = hostName`) konfigurierten Ein Server erwartet die für ihn (`location = hostName`) konfigurierten
Container. systemd versucht sie zu starten. Das wird erst nach Container. systemd versucht sie zu starten. Das wird erst nach
`build-container` funktionieren, welches das Rootfs anlegt. `build-container` funktionieren, welches das Rootfs anlegt.

View File

@ -26,11 +26,11 @@ Alle Stecker im Haus sind in Schema A gecrimpt.
| | ![][gi] B 2.05.02 | ![][gi] UVB 1.09 | | 14 | | | ![][gi] B 2.05.02 | ![][gi] UVB 1.09 | | 14 |
| ![][ri] B 4.02.01 *v* | ![][gi] B 2.05.05 | ![][gi] UVB 1.10 | | 15 | | ![][ri] B 4.02.01 *v* | ![][gi] B 2.05.05 | ![][gi] UVB 1.10 | | 15 |
| ![][ri] B 4.01.01 *v* | ![][gi] B 2.05.06 | ![][gi] 1.06 | | 16 | | ![][ri] B 4.01.01 *v* | ![][gi] B 2.05.06 | ![][gi] 1.06 | | 16 |
| ![][ri] B 4.03.01 *v* | ![][gi] B 2.05.03 *v* | ![][gi] 1.16 *v* | | 17 | | ![][ri] B 4.03.01 | ![][gi] B 2.05.03 *v* | | | 17 |
| ![][ri] B 4.04.01 *v* | ![][gi] B 2.05.07 *v* | | | 18 | | ![][ri] B 4.04.01 *v* | ![][gi] B 2.05.07 *v* | | | 18 |
| ![][ri] B 4.05.02 *v* | ![][gi] B 2.06 | | | 19 | | ![][ri] B 4.05.02 *v* | ![][gi] B 2.06 | | | 19 |
| ![][ri] B 4.06.01 *v* | ![][ri] B 2.07 | | | 20 | | ![][ri] B 4.06.01 | ![][ri] B 2.07 | | | 20 |
| ![][ri] B 4.07.05 *v* | | | | 21 | | ![][ri] B 4.07.05 | | | | 21 |
| ![][ri] B 4.08.01 | | | | 22 | | ![][ri] B 4.08.01 | | | | 22 |
| ![][ri] B 4.09.01 *v* | | | | 23 | | ![][ri] B 4.09.01 *v* | | | | 23 |
| ![][ri] B 4.10.01 *v* | | | | 24 | | ![][ri] B 4.10.01 *v* | | | | 24 |

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,4 @@
{ config, lib, ... }: { lib, ... }:
let
# https://github.com/NixOS/nixpkgs/pull/206965
concatMapAttrsRecursive = with lib; f: flip pipe [ (mapAttrs f) attrValues (foldl' recursiveUpdate { }) ];
in
{ {
imports = [ imports = [
# Secrets # Secrets
@ -14,8 +9,7 @@ in
./switch.nix ./switch.nix
./ap.nix ./ap.nix
./server.nix ./server.nix
] ] ++
# IP networks # IP networks
++ lib.filesystem.listFilesRecursive ./net; lib.filesystem.listFilesRecursive ./net;
} }

View File

@ -8,74 +8,65 @@
fixed-hosts = { fixed-hosts = {
"172.22.99.96" = "08:00:27:bb:8c:b3"; "172.22.99.96" = "08:00:27:bb:8c:b3";
"172.22.99.98" = "08:00:27:aa:90:e2"; "172.22.99.98" = "08:00:27:aa:90:e2";
# "astrom" = "aa:00:5b:08:f0:5c"; "astrom.hq.c3d2.de" = "aa:00:5b:08:f0:5c";
# "astron" = "aa:00:5b:08:f0:5b"; "astron.hq.c3d2.de" = "aa:00:5b:08:f0:5b";
# "batman" = "5c:cf:7f:c0:05:28"; "batman.hq.c3d2.de" = "5c:cf:7f:c0:05:28";
# "beere" = "b8:27:eb:ac:65:d2"; "beere.hq.c3d2.de" = "b8:27:eb:ac:65:d2";
# "beere2" = "b8:27:eb:53:0b:27"; "beere2.hq.c3d2.de" = "b8:27:eb:53:0b:27";
# "bender.hq.c3de.de" = "00:23:df:7e:c8:0a"; "bender.hq.c3de.de" = "00:23:df:7e:c8:0a";
# "cider" = "00:0d:93:75:ee:fa"; "cider.hq.c3d2.de" = "00:0d:93:75:ee:fa";
"dacbert" = "dc:a6:32:e0:46:bf"; "dacbert.hq.c3d2.de" = "dc:a6:32:31:b6:32";
"dn42" = "aa:00:42:7a:32:46"; "dn42.hq.c3d2.de" = "aa:00:42:7a:32:46";
# "drucker" = "00:23:c3:d2:12:0f"; "drucker.hq.c3d2.de" = "00:23:c3:d2:12:0f";
# "feile" = "aa:00:5b:12:c1:f7"; "feile.hq.c3d2.de" = "aa:00:5b:12:c1:f7";
# "fernandopoo" = "aa:00:f7:52:85:27"; "fernandopoo.hq.c3d2.de" = "aa:00:f7:52:85:27";
# "fhem" = "b8:27:eb:9e:8b:db"; "fhem.hq.c3d2.de" = "b8:27:eb:9e:8b:db";
# "git" = "aa:00:47:d8:57:10"; "git.hq.c3d2.de" = "aa:00:47:d8:57:10";
"glotzbert" = "90:1b:0e:88:da:0a"; "glotzbert.hq.c3d2.de" = "ec:a8:6b:fe:b4:cb";
# "wled-nix-snowflake" = "44:17:93:10:77:e8"; "icq.hq.c3d2.de" = "aa:00:30:f6:27:89";
# "wled-fairy-dust" = "3c:61:05:e3:2f:ad"; "jabber1.hq.c3d2.de" = "aa:00:0b:19:8f:14";
# "wled-warnbert" = "3c:61:05:fc:21:37"; "jabber2.hq.c3d2.de" = "aa:00:3d:6a:23:b8";
# "wled-matrix" = "e8:db:84:e4:f4:30"; "knot.hq.c3d2.de" = "52:54:cf:fd:ce:3f";
# "ledball1" = "b8:27:eb:53:0b:27"; "ledball1.hq.c3d2.de" = "b8:27:eb:53:0b:27";
# Beleuchtungskiste auf Traverse über Fernseher "ledbeere.hq.c3d2.de" = "b8:27:eb:60:99:59";
# "ledbeere" = "b8:27:eb:60:99:59"; "leviathan.hq.c3d2.de" = "00:ff:08:31:db:e5";
# "leviathan" = "00:ff:08:31:db:e5"; "lisbeth.hq.c3d2.de" = "b8:27:eb:a5:ee:5c";
# "lisbeth" = "b8:27:eb:a5:ee:5c"; "marenz-build.hq.c3d2.de" = "44:1e:a1:59:2e:e8";
# "marenz-build" = "44:1e:a1:59:2e:e8"; "matemat.hq.c3d2.de" = "a2:1b:7c:e8:19:72";
# "matemat" = "a2:1b:7c:e8:19:72"; "minecraft.hq.c3d2.de" = "4a:57:d3:64:fe:e9";
# "minecraft" = "4a:57:d3:64:fe:e9"; "moleflap.hq.c3d2.de" = "aa:00:0d:b1:6c:67";
# "moleflap" = "aa:00:0d:b1:6c:67"; "monit.hq.c3d2.de" = "00:23:ae:94:e7:19";
# "monit" = "00:23:ae:94:e7:19"; "public-access-proxy.hq.c3d2.de" = "12:24:5f:bd:9b:e7";
"pipebert" = "ec:a8:6b:fe:b4:cb"; "pulsebert.hq.c3d2.de" = "b8:27:eb:16:31:61";
# "public-access-proxy" = "12:24:5f:bd:9b:e7"; "ruststripe1.hq.c3d2.de" = "06:32:0e:39:21:69";
"pulsebert" = "b8:27:eb:16:31:61"; "schalter.hq.c3d2.de" = "b8:27:eb:4c:be:ff";
# "ruststripe1" = "06:32:0e:39:21:69"; "semanta.hq.c3d2.de" = "00:ff:e4:bb:ea:2a";
"schalter" = "b8:27:eb:ac:65:d2"; "server2.hq.c3d2.de" = "d0:67:e5:f3:57:10";
# "semanta" = "00:ff:e4:bb:ea:2a"; "server3.hq.c3d2.de" = "e4:1f:13:2e:4f:c0";
# "server2" = "d0:67:e5:f3:57:10"; "server4.hq.c3d2.de" = "00:9c:02:a9:26:01";
# "server3" = "e4:1f:13:2e:4f:c0"; "sharing.hq.c3d2.de" = "00:23:c3:d2:75:18";
# "server4" = "00:9c:02:a9:26:01"; "sofafon.hq.c3d2.de" = "b8:27:eb:23:8d:01";
# "sharing" = "00:23:c3:d2:75:18"; "storage2.hq.c3d2.de" = "42:5e:0f:4e:f3:cc";
# "sofafon" = "b8:27:eb:23:8d:01"; "ustriper.hq.c3d2.de" = "aa:bb:95:33:bb:aa";
# "storage2" = "42:5e:0f:4e:f3:cc"; "wiefelspuetz.hq.c3d2.de" = "aa:00:7f:01:8a:d0";
# "ustriper" = "aa:bb:95:33:bb:aa"; "wormhole.hq.c3d2.de" = "00:23:c3:d2:00:76";
# "wiefelspuetz" = "aa:00:7f:01:8a:d0"; "www1.hq.c3d2.de" = "aa:00:13:8b:03:47";
# "wormhole" = "00:23:c3:d2:00:76";
# "www1" = "aa:00:13:8b:03:47";
# "riscbert" = "6c:cf:39:00:05:95";
}; };
time = 300; time = 86400;
max-time = 30 * 24 * 3600; max-time = 2592000;
router = "c3d2-gw3"; router = "c3d2-anon";
}; };
domainName = "c3d2.zentralwerk.org"; domainName = "c3d2.zentralwerk.org";
dynamicDomain = true; dynamicDomain = true;
subnet4 = "172.22.99.0/24"; subnet4 = "172.22.99.0/24";
hosts4 = { hosts4 = {
bgp = "172.22.99.250";
c3d2-anon = "172.22.99.1"; c3d2-anon = "172.22.99.1";
c3d2-gw1 = "172.22.99.2"; c3d2-gw1 = "172.22.99.2";
c3d2-gw2 = "172.22.99.3"; c3d2-gw2 = "172.22.99.3";
c3d2-gw3 = "172.22.99.4"; c3d2-gw3 = "172.22.99.4";
dacbert = "172.22.99.203";
schalter = "172.22.99.204";
glotzbert = "172.22.99.205";
pulsebert = "172.22.99.208";
pipebert = "172.22.99.209";
bgp = "172.22.99.250";
dn42 = "172.22.99.253"; dn42 = "172.22.99.253";
}; };
ipv6Router = "c3d2-gw3";
hosts6.dn42 = { hosts6.dn42 = {
bgp = "fd23:42:c3d2:523::c3d2:ff0b"; bgp = "fd23:42:c3d2:523::c3d2:ff0b";
c3d2-anon = "fd23:42:c3d2:523::c3d2:1"; c3d2-anon = "fd23:42:c3d2:523::c3d2:1";
@ -89,12 +80,12 @@
c3d2-gw1 = "2a00:8180:2c00:223::c3d2:2"; c3d2-gw1 = "2a00:8180:2c00:223::c3d2:2";
c3d2-gw2 = "2a00:8180:2c00:223::c3d2:3"; c3d2-gw2 = "2a00:8180:2c00:223::c3d2:3";
c3d2-gw3 = "2a00:8180:2c00:223::c3d2:4"; c3d2-gw3 = "2a00:8180:2c00:223::c3d2:4";
glotzbert = "2a00:8180:2c00:223:e1ad:6c2b:af9f:2d13";
pipebert = "2a00:8180:2c00:223:eea8:6bff:fefe:b4cb";
}; };
hosts6.yggdrasil.c3d2-gw3 = "30c:c3d2:b946:76d0::1";
subnets6 = { subnets6 = {
dn42 = "fd23:42:c3d2:523::/64"; dn42 = "fd23:42:c3d2:523::/64";
up4 = "2a00:8180:2c00:223::/64"; up4 = "2a00:8180:2c00:223::/64";
yggdrasil = "30c:c3d2:b946:76d0::/64";
}; };
}; };
@ -121,21 +112,21 @@
c3d2.hwaddr = "0A:14:48:01:21:01"; c3d2.hwaddr = "0A:14:48:01:21:01";
core.hwaddr = "0A:14:48:01:21:00"; core.hwaddr = "0A:14:48:01:21:00";
}; };
ospf.allowedUpstreams = [ "flpk-gw" "freifunk" "upstream4" "upstream3" "anon1" ]; ospf.allowedUpstreams = [ "upstream3" "upstream4" "upstream1" "anon1" "freifunk" ];
}; };
c3d2-gw2 = makeGateway { c3d2-gw2 = makeGateway {
interfaces = { interfaces = {
c3d2.hwaddr = "0A:14:48:01:21:03"; c3d2.hwaddr = "0A:14:48:01:21:03";
core.hwaddr = "0A:14:48:01:21:02"; core.hwaddr = "0A:14:48:01:21:02";
}; };
ospf.allowedUpstreams = [ "upstream3" "upstream4" "anon1" "freifunk" ]; ospf.allowedUpstreams = [ "upstream1" "upstream3" "upstream4" "anon1" "freifunk" ];
}; };
c3d2-gw3 = makeGateway { c3d2-gw3 = makeGateway {
interfaces = { interfaces = {
c3d2.hwaddr = "0A:14:48:01:21:05"; c3d2.hwaddr = "0A:14:48:01:21:05";
core.hwaddr = "0A:14:48:01:21:04"; core.hwaddr = "0A:14:48:01:21:04";
}; };
ospf.allowedUpstreams = [ "upstream4" "upstream3" "anon1" "freifunk" ]; ospf.allowedUpstreams = [ "upstream4" "upstream3" "upstream1" "anon1" "freifunk" ];
}; };
}; };
} }

View File

@ -1,47 +0,0 @@
{
site.net.c3d2iot = {
dhcp = {
start = "10.22.0.2";
end = "10.22.255.253";
router = "iot-gw";
server = "iot-gw";
# devices don't often change and a missing DNS record causes trouble
time = 3600;
max-time = 24 * 3600;
};
dynamicDomain = true;
domainName = "c3d2iot.zentralwerk.org";
hosts4 = {
iot-gw = "10.22.0.1";
};
hosts6 = {
dn42 = {
iot-gw = "fd23:42:c3d2:587:ffff:ffff:ffff:ffff";
};
};
subnet4 = "10.22.0.0/16";
subnets6 = {
dn42 = "fd23:42:c3d2:587::/64";
up4 = "2a00:8180:2c00:287::/64";
};
};
site.hosts.iot-gw = {
# TODO: needs to be done more granular, aka allow c3d2 and serv network
# firewall.enable = true;
interfaces = {
core = {
hwaddr = "0A:22:48:01:24:01";
type = "veth";
};
c3d2iot = {
hwaddr = "0A:22:48:01:24:00";
type = "veth";
};
};
ospf = {
allowedUpstreams = [ "upstream4" "upstream3" "anon1" ];
};
role = "container";
};
}

View File

@ -4,18 +4,10 @@ let
in in
{ {
site.net.cluster = { site.net.cluster = {
ipv6Router = "cls-gw";
domainName = "cluster.zentralwerk.org"; domainName = "cluster.zentralwerk.org";
extraRecords = map (host: { extraRecords = map (host: {
data = { data = "1 1 6789 ${host}";
service = "ceph-mon"; name = "_ceph-mon._tcp";
proto = "tcp";
priority = 1;
weight = 1;
port = 6789;
target = host;
};
name = "@";
type = "SRV"; type = "SRV";
}) cephMonServers }) cephMonServers
++ ++
@ -133,7 +125,7 @@ in
let let
makeServer = { makeServer = {
role = "client"; role = "client";
model = "nixos"; model = "proxmox";
interfaces = builtins.foldl' (interfaces: net: interfaces = builtins.foldl' (interfaces: net:
interfaces // { interfaces // {
"${net}".type = "bridge"; "${net}".type = "bridge";
@ -144,13 +136,10 @@ in
"mgmt" "mgmt"
"serv" "serv"
"c3d2" "c3d2"
"c3d2iot"
"pub" "pub"
"priv23" "priv23"
"priv31" "priv31"
"priv45"
"bmx" "bmx"
"flpk"
]; ];
}; };
in { in {
@ -166,7 +155,7 @@ in
type = "veth"; type = "veth";
}; };
}; };
ospf.allowedUpstreams = [ "upstream4" "upstream3" "anon1" "freifunk" ]; ospf.allowedUpstreams = [ "upstream4" "upstream1" "upstream3" "anon1" "freifunk" ];
}; };
server3 = makeServer; server3 = makeServer;
server5 = makeServer; server5 = makeServer;
@ -174,6 +163,5 @@ in
server7 = makeServer; server7 = makeServer;
server8 = makeServer; server8 = makeServer;
server9 = makeServer; server9 = makeServer;
server10 = makeServer;
}; };
} }

View File

@ -1,38 +0,0 @@
{
site.net.coloradio = {
domainName = "coloradio.zentralwerk.org";
subnet4 = "192.168.9.0/24";
hosts4 = {
coloradio-gw = "192.168.9.1";
coloradio-in = "192.168.9.2";
};
ipv6Router = "coloradio-gw";
subnets6.dn42 = "fd23:42:c3d2:590::/64";
hosts6.dn42 = {
coloradio-gw = "fd23:42:c3d2:590::1";
};
};
site.hosts = {
coloradio-gw = {
role = "container";
interfaces = {
core = {
type = "veth";
hwaddr = "0A:14:48:01:06:08";
gw4 = null;
gw6 = null;
};
coloradio = {
type = "veth";
hwaddr = "0A:14:48:01:06:09";
gw4 = null;
gw6 = null;
};
};
ospf.allowedUpstreams =
[ "upstream4" "upstream3" "freifunk" ];
};
};
}

View File

@ -49,13 +49,6 @@
priv40-gw = "172.20.72.61"; priv40-gw = "172.20.72.61";
priv41-gw = "172.20.72.65"; priv41-gw = "172.20.72.65";
priv42-gw = "172.20.72.67"; priv42-gw = "172.20.72.67";
priv43-gw = "172.20.72.68";
priv44-gw = "172.20.72.70";
priv45-gw = "172.20.72.72";
priv46-gw = "172.20.72.73";
priv47-gw = "172.20.72.74";
priv48-gw = "172.20.72.75";
priv49-gw = "172.20.72.76";
priv5-gw = "172.20.72.15"; priv5-gw = "172.20.72.15";
priv6-gw = "172.20.72.16"; priv6-gw = "172.20.72.16";
priv7-gw = "172.20.72.17"; priv7-gw = "172.20.72.17";
@ -69,12 +62,12 @@
server6 = "172.20.72.56"; server6 = "172.20.72.56";
server7 = "172.20.72.57"; server7 = "172.20.72.57";
server8 = "172.20.72.58"; server8 = "172.20.72.58";
server9 = "172.20.72.59";
upstream1 = "172.20.72.6";
upstream2 = "172.20.72.10";
upstream3 = "172.20.72.11"; upstream3 = "172.20.72.11";
upstream4 = "172.20.72.12"; upstream4 = "172.20.72.12";
coloradio-gw = "172.20.72.62"; yggdrasil = "172.20.72.62";
vpn-gw = "172.20.72.69";
flpk-gw = "172.20.72.71";
iot-gw = "172.20.72.77";
}; };
hosts6 = { hosts6 = {
dn42 = { dn42 = {
@ -84,10 +77,8 @@
c3d2-gw1 = "fd23:42:c3d2:581::c3d2:1"; c3d2-gw1 = "fd23:42:c3d2:581::c3d2:1";
c3d2-gw2 = "fd23:42:c3d2:581::c3d2:2"; c3d2-gw2 = "fd23:42:c3d2:581::c3d2:2";
c3d2-gw3 = "fd23:42:c3d2:581::c3d2:3"; c3d2-gw3 = "fd23:42:c3d2:581::c3d2:3";
cls-gw = "fd23:42:c3d2:581::c3d2:4";
freifunk = "fd23:42:c3d2:581:8000::1"; freifunk = "fd23:42:c3d2:581:8000::1";
mgmt-gw = "fd23:42:c3d2:581::8:3"; mgmt-gw = "fd23:42:c3d2:581::8:3";
iot-gw = "fd23:42:c3d2:581::8:7";
priv1-gw = "fd23:42:c3d2:581::c:0"; priv1-gw = "fd23:42:c3d2:581::c:0";
priv10-gw = "fd23:42:c3d2:581::c:9"; priv10-gw = "fd23:42:c3d2:581::c:9";
priv11-gw = "fd23:42:c3d2:581::c:a"; priv11-gw = "fd23:42:c3d2:581::c:a";
@ -125,13 +116,6 @@
priv40-gw = "fd23:42:c3d2:581::c:27"; priv40-gw = "fd23:42:c3d2:581::c:27";
priv41-gw = "fd23:42:c3d2:581::c:28"; priv41-gw = "fd23:42:c3d2:581::c:28";
priv42-gw = "fd23:42:c3d2:581::c:29"; priv42-gw = "fd23:42:c3d2:581::c:29";
priv43-gw = "fd23:42:c3d2:581::c:2a";
priv44-gw = "fd23:42:c3d2:581::c:2b";
priv45-gw = "fd23:42:c3d2:581::c:2c";
priv46-gw = "fd23:42:c3d2:581::c:2d";
priv47-gw = "fd23:42:c3d2:581::c:2e";
priv48-gw = "fd23:42:c3d2:581::c:2f";
priv49-gw = "fd23:42:c3d2:581::c:30";
priv5-gw = "fd23:42:c3d2:581::c:4"; priv5-gw = "fd23:42:c3d2:581::c:4";
priv6-gw = "fd23:42:c3d2:581::c:5"; priv6-gw = "fd23:42:c3d2:581::c:5";
priv7-gw = "fd23:42:c3d2:581::c:6"; priv7-gw = "fd23:42:c3d2:581::c:6";
@ -139,10 +123,11 @@
priv9-gw = "fd23:42:c3d2:581::c:8"; priv9-gw = "fd23:42:c3d2:581::c:8";
pub-gw = "fd23:42:c3d2:581::8:2"; pub-gw = "fd23:42:c3d2:581::8:2";
serv-gw = "fd23:42:c3d2:581::8:1"; serv-gw = "fd23:42:c3d2:581::8:1";
upstream1 = "fd23:42:c3d2:581::b:0";
upstream2 = "fd23:42:c3d2:581::b:1";
upstream3 = "fd23:42:c3d2:581::b:2"; upstream3 = "fd23:42:c3d2:581::b:2";
upstream4 = "fd23:42:c3d2:581::b:3"; upstream4 = "fd23:42:c3d2:581::b:3";
vpn-gw = "fd23:42:c3d2:581:9001::1"; yggdrasil = "fd23:42:c3d2:581:9000::1";
coloradio-gw = "fd23:42:c3d2:581:9009::1";
}; };
up4 = { up4 = {
anon1 = "2a00:8180:2c00:281::9:1"; anon1 = "2a00:8180:2c00:281::9:1";
@ -154,7 +139,6 @@
cls-gw = "2a00:8180:2c00:281::8:4"; cls-gw = "2a00:8180:2c00:281::8:4";
freifunk = "2a00:8180:2c00:281:8000::1"; freifunk = "2a00:8180:2c00:281:8000::1";
mgmt-gw = "2a00:8180:2c00:281::8:3"; mgmt-gw = "2a00:8180:2c00:281::8:3";
iot-gw = "2a00:8180:2c00:281::8:7";
priv1-gw = "2a00:8180:2c00:281::c:0"; priv1-gw = "2a00:8180:2c00:281::c:0";
priv10-gw = "2a00:8180:2c00:281::c:9"; priv10-gw = "2a00:8180:2c00:281::c:9";
priv11-gw = "2a00:8180:2c00:281::c:a"; priv11-gw = "2a00:8180:2c00:281::c:a";
@ -192,22 +176,15 @@
priv40-gw = "2a00:8180:2c00:281::c:27"; priv40-gw = "2a00:8180:2c00:281::c:27";
priv41-gw = "2a00:8180:2c00:281::c:28"; priv41-gw = "2a00:8180:2c00:281::c:28";
priv42-gw = "2a00:8180:2c00:281::c:29"; priv42-gw = "2a00:8180:2c00:281::c:29";
priv43-gw = "2a00:8180:2c00:281::c:2a";
priv44-gw = "2a00:8180:2c00:281::c:2b";
priv45-gw = "2a00:8180:2c00:281::c:2c";
priv46-gw = "2a00:8180:2c00:281::c:2d";
priv47-gw = "2a00:8180:2c00:281::c:2e";
priv48-gw = "2a00:8180:2c00:281::c:2f";
priv49-gw = "2a00:8180:2c00:281::c:30";
priv5-gw = "2a00:8180:2c00:281::c:4"; priv5-gw = "2a00:8180:2c00:281::c:4";
priv6-gw = "2a00:8180:2c00:281::c:5"; priv6-gw = "2a00:8180:2c00:281::c:5";
priv7-gw = "2a00:8180:2c00:281::c:6"; priv7-gw = "2a00:8180:2c00:281::c:6";
priv8-gw = "2a00:8180:2c00:281::c:7"; priv8-gw = "2a00:8180:2c00:281::c:7";
priv9-gw = "2a00:8180:2c00:281::c:8"; priv9-gw = "2a00:8180:2c00:281::c:8";
serv-gw = "2a00:8180:2c00:281::8:1"; serv-gw = "2a00:8180:2c00:281::8:1";
upstream1 = "2a00:8180:2c00:281::b:0";
upstream4 = "2a00:8180:2c00:281::b:1"; upstream4 = "2a00:8180:2c00:281::b:1";
vpn-gw = "2a00:8180:2c00:281:9001::1"; yggdrasil = "2a00:8180:2c00:281:9000::1";
coloradio-gw = "2a00:8180:2c00:281:9009::1";
}; };
}; };
subnet4 = "172.20.72.0/25"; subnet4 = "172.20.72.0/25";
@ -238,10 +215,10 @@
}; };
ospf = { ospf = {
allowedUpstreams = allowedUpstreams =
[ "upstream4" "upstream3" "anon1" "freifunk" ]; [ "upstream4" "upstream1" "upstream3" "anon1" "freifunk" ];
stubNets4 = [ "172.20.0.0/14" "10.0.0.0/8" ]; stubNets4 = [ "172.20.0.0/14" "10.0.0.0/8" ];
stubNets6 = stubNets6 =
[ "fd00::/8" "2a00:8180:2c00:200::/56" ]; [ "fd00::/8" "2a02:8106:208:5200::/56" "2a02:8106:211:e900::/56" ];
}; };
role = "container"; role = "container";
}; };

View File

@ -1,65 +0,0 @@
{
site.net.flpk = {
domainName = "flpk.zentralwerk.org";
ipv6Router = "flpk-gw";
subnet4 = "45.158.40.160/27";
# we get a /56
subnets6.flpk = "2a0f:5382:acab:1400::/64";
hosts4 = {
flpk-gw = "45.158.40.160";
notice-me-senpai = "45.158.40.162"; # tlms monitoring
sshlog = "45.158.40.163";
caveman = "45.158.40.164";
# tlms-37c3-ctf vm on server9
ctf = "45.158.40.165";
mastodon = "45.158.40.166";
c3d2-web = "45.158.40.167";
mail = "45.158.40.168";
dresden-zone-dns = "45.158.40.169";
# server7 = "45.158.40.170"; # unused
rtrlab = "45.158.40.171"; # temporary
};
hosts6.flpk = {
flpk-gw = "2a0f:5382:acab:1400::c3d2";
notice-me-senpai = "2a0f:5382:acab:1400:2de:5bff:fef9:e23e"; # tlms-monitoring
sshlog = "2a0f:5382:acab:1400::22";
caveman = "2a0f:5382:acab:1400::a4";
# tlms-37c3-ctf vm on server9
ctf = "2a0f:5382:acab:1400::a5";
mastodon = "2a0f:5382:acab:1400::a6";
c3d2-web = "2a0f:5382:acab:1400::a7";
# mail = "2a0f:5382:acab:1400::a8"; # we don't have an PTR for IPv6 and it gets way more often marked as spam
dresden-zone-dns = "2a0f:5382:acab:1400::a9";
# server7 = "2a0f:5382:acab:1400::aa";
rtrlab = "2a0f:5382:acab:1400::ab";
};
};
site.hosts.flpk-gw = {
interfaces = {
core = {
hwaddr = "0A:14:48:b7:e4:91";
type = "veth";
};
flpk = {
hwaddr = "0A:14:48:01:16:01";
type = "veth";
};
up-flpk = {
type = "wireguard";
upstream = {
provider = "flpk";
noNat = {
subnets4 = [ "45.158.40.160/27" ];
subnets6 = [ "2a0f:5382:acab:1400::/56" ];
};
};
};
};
ospf = {
allowedUpstreams = [ "upstream4" "upstream3" "freifunk" ];
upstreamInstance = 2;
};
role = "container";
};
}

View File

@ -63,16 +63,7 @@
ap62 = "10.0.0.102"; ap62 = "10.0.0.102";
ap63 = "10.0.0.103"; ap63 = "10.0.0.103";
ap64 = "10.0.0.104"; ap64 = "10.0.0.104";
ap65 = "10.0.0.105";
ap66 = "10.0.0.106";
ap67 = "10.0.0.107";
ap68 = "10.0.0.108";
ap69 = "10.0.0.109";
ap7 = "10.0.0.47"; ap7 = "10.0.0.47";
ap70 = "10.0.0.110";
ap71 = "10.0.0.111";
ap72 = "10.0.0.112";
ap73 = "10.0.0.113";
ap8 = "10.0.0.48"; ap8 = "10.0.0.48";
ap9 = "10.0.0.49"; ap9 = "10.0.0.49";
logging = "10.0.0.251"; logging = "10.0.0.251";
@ -104,10 +95,6 @@
switch-c3d2-main = "10.0.0.14"; switch-c3d2-main = "10.0.0.14";
switch-d1 = "10.0.0.13"; switch-d1 = "10.0.0.13";
switch-dach = "10.0.0.17"; switch-dach = "10.0.0.17";
switch-b3 = "10.0.0.18";
switch-ds1 = "10.0.0.20";
switch-ds2 = "10.0.0.21";
switch-ds3 = "10.0.0.22";
}; };
hosts6 = { hosts6 = {
dn42 = { dn42 = {
@ -172,16 +159,7 @@
ap62 = "fd23:42:c3d2:580::4:3e"; ap62 = "fd23:42:c3d2:580::4:3e";
ap63 = "fd23:42:c3d2:580::4:3f"; ap63 = "fd23:42:c3d2:580::4:3f";
ap64 = "fd23:42:c3d2:580::4:40"; ap64 = "fd23:42:c3d2:580::4:40";
ap65 = "fd23:42:c3d2:580::4:41";
ap66 = "fd23:42:c3d2:580::4:42";
ap67 = "fd23:42:c3d2:580::4:43";
ap68 = "fd23:42:c3d2:580::4:44";
ap69 = "fd23:42:c3d2:580::4:45";
ap7 = "fd23:42:c3d2:580::4:7"; ap7 = "fd23:42:c3d2:580::4:7";
ap70 = "fd23:42:c3d2:580::4:46";
ap71 = "fd23:42:c3d2:580::4:47";
ap72 = "fd23:42:c3d2:580::4:48";
ap73 = "fd23:42:c3d2:580::4:49";
ap8 = "fd23:42:c3d2:580::4:8"; ap8 = "fd23:42:c3d2:580::4:8";
ap9 = "fd23:42:c3d2:580::4:9"; ap9 = "fd23:42:c3d2:580::4:9";
mgmt-gw = "fd23:42:c3d2:580:ffff:ffff:ffff:ffff"; mgmt-gw = "fd23:42:c3d2:580:ffff:ffff:ffff:ffff";
@ -213,7 +191,7 @@
}; };
ospf = { ospf = {
allowedUpstreams = allowedUpstreams =
[ "upstream4" "upstream3" "anon1" "freifunk" ]; [ "upstream4" "upstream1" "upstream3" "anon1" "freifunk" ];
}; };
role = "container"; role = "container";
}; };

View File

@ -1,6 +1,6 @@
{ lib, ... }: { lib, ... }:
let let
privCount = 49; privCount = 42;
seq = n: max: seq = n: max:
if n <= max if n <= max
then [ n ] ++ seq (n + 1) max then [ n ] ++ seq (n + 1) max
@ -16,9 +16,9 @@ lib.mkMerge (
site.net."priv${toString n}" = { site.net."priv${toString n}" = {
dhcp = { dhcp = {
server = "priv${toString n}-gw"; server = "priv${toString n}-gw";
time = 300; time = 120;
max-time = 60 * 24 * 3600; max-time = 86400;
router = "priv${toString n}-gw"; router = "priv${toString n}-gw.priv${toString n}";
}; };
domainName = "priv${toString n}.zentralwerk.org"; domainName = "priv${toString n}.zentralwerk.org";
dynamicDomain = true; dynamicDomain = true;
@ -38,7 +38,7 @@ lib.mkMerge (
core.type = "veth"; core.type = "veth";
"priv${toString n}".type = "veth"; "priv${toString n}".type = "veth";
}; };
ospf.allowedUpstreams = [ "upstream4" "upstream3" "anon1" "freifunk" ]; ospf.allowedUpstreams = [ "upstream4" "upstream3" "upstream1" "anon1" "freifunk" ];
}; };
} }
) (seq 1 privCount) ) (seq 1 privCount)
@ -58,12 +58,10 @@ lib.mkMerge (
subnet4 = "172.20.75.0/27"; subnet4 = "172.20.75.0/27";
dhcp = { dhcp = {
start = "172.20.75.2"; start = "172.20.75.2";
end = "172.20.75.30"; end = "172.20.75.31";
fixed-hosts = { fixed-hosts = {
"172.20.75.2" = "ac:1f:6b:dc:93:8e";
"172.20.75.3" = "ac:1f:6b:dc:95:de";
"172.20.75.9" = "ac:1f:6b:dc:95:df";
"172.20.75.7" = "60:33:4b:0b:cd:fc"; "172.20.75.7" = "60:33:4b:0b:cd:fc";
"172.20.75.9" = "00:11:32:22:95:79";
}; };
}; };
}; };
@ -204,6 +202,7 @@ lib.mkMerge (
dhcp = { dhcp = {
start = "172.20.73.194"; start = "172.20.73.194";
end = "172.20.73.254"; end = "172.20.73.254";
max-time = lib.mkForce 2592000;
}; };
}; };
priv20 = { priv20 = {
@ -238,10 +237,9 @@ lib.mkMerge (
end = "172.20.73.190"; end = "172.20.73.190";
fixed-hosts = { fixed-hosts = {
"172.20.73.162" = "da:2c:3a:2c:87:22"; "172.20.73.162" = "da:2c:3a:2c:87:22";
"172.20.73.163" = "b8:27:eb:16:31:61"; "172.20.73.163" = "ca:9f:27:b2:bf:6d";
"172.20.73.164" = "ca:71:c4:90:3e:c7"; "172.20.73.164" = "60:01:94:6f:81:a6";
}; };
time = lib.mkForce 900;
}; };
}; };
priv24 = { priv24 = {
@ -305,11 +303,7 @@ lib.mkMerge (
subnet4 = "172.20.75.208/28"; subnet4 = "172.20.75.208/28";
dhcp = { dhcp = {
start = "172.20.75.210"; start = "172.20.75.210";
end = "172.20.75.221"; end = "172.20.75.222";
fixed-hosts = {
# zw-ev-vm
"172.20.75.222" = "92:a8:00:49:a6:61";
};
}; };
}; };
priv32 = { priv32 = {
@ -400,62 +394,6 @@ lib.mkMerge (
end = "172.20.76.46"; end = "172.20.76.46";
}; };
}; };
priv43 = {
hosts4 = { priv43-gw = "172.20.76.97"; };
subnet4 = "172.20.76.96/28";
dhcp = {
start = "172.20.76.98";
end = "172.20.76.110";
};
};
priv44 = {
hosts4 = { priv44-gw = "172.20.77.97"; };
subnet4 = "172.20.77.96/28";
dhcp = {
start = "172.20.77.98";
end = "172.20.77.110";
};
};
priv45 = {
hosts4 = { priv45-gw = "172.20.77.161"; };
subnet4 = "172.20.77.160/28";
dhcp = {
start = "172.20.77.162";
end = "172.20.77.174";
};
};
priv46 = {
hosts4 = { priv46-gw = "172.20.77.225"; };
subnet4 = "172.20.77.224/28";
dhcp = {
start = "172.20.77.226";
end = "172.20.77.238";
};
};
priv47 = {
hosts4 = { priv47-gw = "172.20.76.161"; };
subnet4 = "172.20.76.160/28";
dhcp = {
start = "172.20.76.162";
end = "172.20.76.174";
};
};
priv48 = {
hosts4 = { priv48-gw = "172.20.77.33"; };
subnet4 = "172.20.77.32/28";
dhcp = {
start = "172.20.77.34";
end = "172.20.77.46";
};
};
priv49 = {
hosts4 = { priv49-gw = "172.20.76.49"; };
subnet4 = "172.20.76.48/28";
dhcp = {
start = "172.20.76.50";
end = "172.20.76.62";
};
};
}; };
site.hosts = { site.hosts = {
@ -574,7 +512,7 @@ lib.mkMerge (
hwaddr = "0A:14:47:02:2A:19"; hwaddr = "0A:14:47:02:2A:19";
}; };
}; };
ospf.allowedUpstreams = [ "upstream3" "upstream4" "anon1" "freifunk" ]; ospf.allowedUpstreams = [ "upstream3" "upstream4" "upstream1" "anon1" "freifunk" ];
}; };
priv18-gw = { priv18-gw = {
interfaces = { interfaces = {
@ -726,48 +664,6 @@ lib.mkMerge (
priv42.hwaddr = "0A:14:48:01:2A:51"; priv42.hwaddr = "0A:14:48:01:2A:51";
}; };
}; };
priv43-gw = {
interfaces = {
core.hwaddr = "0A:14:48:01:2A:52";
priv43.hwaddr = "0A:14:48:01:2A:53";
};
};
priv44-gw = {
interfaces = {
core.hwaddr = "0A:14:48:01:2A:54";
priv44.hwaddr = "0A:14:48:01:2A:55";
};
};
priv45-gw = {
interfaces = {
core.hwaddr = "0A:14:48:01:2A:56";
priv45.hwaddr = "0A:14:48:01:2A:57";
};
};
priv46-gw = {
interfaces = {
core.hwaddr = "0A:14:48:01:2A:58";
priv46.hwaddr = "0A:14:48:01:2A:59";
};
};
priv47-gw = {
interfaces = {
core.hwaddr = "0A:14:48:01:2A:5A";
priv47.hwaddr = "0A:14:48:01:2A:5B";
};
};
priv48-gw = {
interfaces = {
core.hwaddr = "0A:14:48:01:2A:5C";
priv48.hwaddr = "0A:14:48:01:2A:5D";
};
};
priv49-gw = {
interfaces = {
core.hwaddr = "0A:14:48:01:2A:5E";
priv49.hwaddr = "0A:14:48:01:2A:5F";
};
};
}; };
} ] } ]
) )

View File

@ -1,31 +1,19 @@
{ {
site.net.pub = { site.net.pub = {
dhcp = { dhcp = {
start = "172.20.78.2"; end = "172.20.79.254";
end = "172.20.79.253"; max-time = 3600;
router = "pub-gw"; router = "pub-gw.pub";
server = "pub-gw"; server = "pub-gw";
time = 120; start = "172.20.78.2";
max-time = 12 * 3600; time = 300;
}; };
domainName = "pub.zentralwerk.org"; domainName = "pub.zentralwerk.org";
dynamicDomain = true; dynamicDomain = true;
hosts4 = { hosts4 = { pub-gw = "172.20.78.1"; };
pub-gw = "172.20.78.1"; hosts6 = { dn42 = { pub-gw = "fd23:42:c3d2:583::1"; }; };
};
hosts6 = {
dn42 = {
pub-gw = "fd23:42:c3d2:583::1";
};
flpk = {
pub-gw = "2a0f:5382:acab:1403::1";
};
};
subnet4 = "172.20.78.0/23"; subnet4 = "172.20.78.0/23";
subnets6 = { subnets6 = { dn42 = "fd23:42:c3d2:583::/64"; };
dn42 = "fd23:42:c3d2:583::/64";
flpk = "2a0f:5382:acab:1403::/64";
};
}; };
site.hosts.pub-gw = { site.hosts.pub-gw = {
@ -41,7 +29,6 @@
}; };
ospf = { ospf = {
allowedUpstreams = [ "anon1" "freifunk" ]; allowedUpstreams = [ "anon1" "freifunk" ];
allowedUpstreams6 = [ "flpk-gw" "anon1" "freifunk" ];
}; };
role = "container"; role = "container";
}; };

View File

@ -1,18 +0,0 @@
{
site.net.roof = {
# not switched, only a wifi
vlan = null;
# leave space for vxlan
mtu = 1574;
subnet4 = "10.0.57.0/24";
hosts4 = {
ap57 = "10.0.57.1";
ap58 = "10.0.57.2";
};
hosts6.dn42 = {
ap57 = "fd23:42:c3d2:584::39";
ap58 = "fd23:42:c3d2:584::40";
};
subnets6.dn42 = "fd23:42:c3d2:584::/64";
};
}

View File

@ -7,136 +7,123 @@
serv-gw = "172.20.73.1"; serv-gw = "172.20.73.1";
dns = "172.20.73.2"; dns = "172.20.73.2";
stats = "172.20.73.3"; stats = "172.20.73.3";
dresden-zone = "172.20.73.4"; radius = "172.20.73.4";
tlms-elastic = "172.20.73.7"; # tlms zeit = "172.20.73.5";
minecraft = "172.20.73.6";
used1 = "172.20.73.7";
dnscache = "172.20.73.8"; dnscache = "172.20.73.8";
tlms-ctfd = "172.20.73.9"; # tlms used2 = "172.20.73.9";
buzzrelay = "172.20.73.15"; used3 = "172.20.73.10";
used4 = "172.20.73.11";
used5 = "172.20.73.12";
logging = "172.20.73.13";
used6 = "172.20.73.14";
c3d2-web = "172.20.73.15";
deployer = "172.20.73.16";
used7 = "172.20.73.17";
used8 = "172.20.73.18";
used9 = "172.20.73.19";
ipa = "172.20.73.20";
matemat = "172.20.73.21"; matemat = "172.20.73.21";
used10 = "172.20.73.22";
used11 = "172.20.73.23";
used12 = "172.20.73.24";
spaceapi = "172.20.73.25"; spaceapi = "172.20.73.25";
used13 = "172.20.73.26";
mucbot = "172.20.73.27"; mucbot = "172.20.73.27";
used14 = "172.20.73.28";
used15 = "172.20.73.29";
used16 = "172.20.73.30";
used17 = "172.20.73.31";
scrape = "172.20.73.32"; scrape = "172.20.73.32";
pretalx = "172.20.73.33"; used19 = "172.20.73.33";
vaultwarden = "172.20.73.34"; used20 = "172.20.73.34";
uranus = "172.20.73.37"; # tlms used21 = "172.20.73.35";
tram-borzoi = "172.20.73.38"; # tlms used22 = "172.20.73.36";
borken-data-hoarder = "172.20.73.39"; # tlms used23 = "172.20.73.37";
matrix = "172.20.73.40"; used24 = "172.20.73.38";
activity-relay = "172.20.73.41"; used25 = "172.20.73.39";
luulaatsch-asterisk = "172.20.73.42"; used26 = "172.20.73.40";
# unused = "172.22.73.41";
# unused = "172.22.73.42";
grafana = "172.20.73.43"; grafana = "172.20.73.43";
kibana = "172.20.73.44";
public-access-proxy = "172.20.73.45"; public-access-proxy = "172.20.73.45";
marenz = "172.20.73.46"; marenz = "172.20.73.46";
network-homepage = "172.20.73.47"; leonos = "172.20.73.47";
home-assistant = "172.20.73.48"; minetest = "172.20.73.48";
hydra = "172.20.73.49"; hydra = "172.20.73.49";
owncast = "172.20.73.50"; netboot = "172.20.73.50";
nfsroot = "172.20.73.51"; vps1 = "172.20.73.51";
ticker = "172.20.73.52"; ticker = "172.20.73.52";
gitea = "172.20.73.53"; gitea = "172.20.73.53";
stream = "172.20.73.54"; stream = "172.20.73.54";
jabber = "172.20.73.55"; jabber = "172.20.73.55";
mobilizon = "172.20.73.56"; mobilizon = "172.20.73.56";
radiobert = "172.20.73.57"; radiobert = "172.20.73.57";
# mail = "172.20.73.58"; mail = "172.20.73.58";
keycloak = "172.20.73.59";
sdrweb = "172.20.73.60"; sdrweb = "172.20.73.60";
knot = "172.20.73.61"; bind = "172.20.73.61";
blogs = "172.20.73.62"; blogs = "172.20.73.62";
staging-data-hoarder = "172.20.73.64"; # tlms
oparl = "172.20.73.65";
hedgedoc = "172.20.73.66";
mediawiki = "172.20.73.67";
gnunet = "172.20.73.68";
data-hoarder = "172.20.73.69"; # tlms
broker = "172.20.73.70";
ftp = "172.20.73.71";
auth = "172.20.73.72";
doubleblind-science = "172.20.73.73";
prometheus = "172.20.73.75";
drone = "172.20.73.77";
# FILL IN THE HOLES BEFORE APPENDING!
}; };
ipv6Router = "serv-gw";
subnets6.dn42 = "fd23:42:c3d2:582::/64"; subnets6.dn42 = "fd23:42:c3d2:582::/64";
subnets6.up4 = "2a00:8180:2c00:282::/64"; subnets6.up4 = "2a00:8180:2c00:282::/64";
hosts6.dn42 = { hosts6.dn42 = {
knot = "fd23:42:c3d2:582:cd7:56ff:fe69:6366"; bind = "fd23:42:c3d2:582:cd7:56ff:fe69:6366";
blogs = "fd23:42:c3d2:582:b8a8:7dff:fee8:5ac2"; blogs = "fd42:42:c3d2:582:b8a8:7dff:fee8:5ac2";
c3d2-web = "fd23:42:c3d2:582:642e:95ff:fe34:49f9";
dns = "fd23:42:c3d2:582:2:0:0:2"; dns = "fd23:42:c3d2:582:2:0:0:2";
dnscache = "fd23:42:c3d2:582:f096:dbff:fee8:427d"; dnscache = "fd23:42:c3d2:582:f096:dbff:fee8:427d";
gitea = "fd23:42:c3d2:582:702a:daff:fe35:83be";
grafana = "fd23:42:c3d2:582:4042:fbff:fe4b:2de8"; grafana = "fd23:42:c3d2:582:4042:fbff:fe4b:2de8";
hydra = "fd23:42:c3d2:582:e2cb:4eff:fe3b:f94b"; hydra = "fd23:42:c3d2:582:e03c:d7ff:fe8e:fe16";
jabber = "fd23:42:c3d2:582:b869:ccff:fe46:902a"; jabber = "fd23:42:c3d2:582:b869:ccff:fe46:902a";
# mail = "fd23:42:c3d2:582:88c0:41ff:fe70:d6cd"; keycloak = "fd23:42:c3d2:582:c48:bbff:fe87:721d";
logging = "fd23:42:c3d2:582:6811:edff:fe40:89c6";
mail = "fd23:42:c3d2:582:88c0:41ff:fe70:d6cd";
matemat = "fd23:42:c3d2:582:f82b:1bff:fedc:8572"; matemat = "fd23:42:c3d2:582:f82b:1bff:fedc:8572";
minetest = "fd23:42:c3d2:582:c3a:42ff:fe5d:b20c";
mobilizon = "fd23:42:c3d2:582:48d1:5cff:fea7:1676"; mobilizon = "fd23:42:c3d2:582:48d1:5cff:fea7:1676";
mongo = "fd23:42:c3d2:582:14ec:c8ff:fe0a:fc5c"; mongo = "fd23:42:c3d2:582:14ec:c8ff:fe0a:fc5c";
mucbot = "fd23:42:c3d2:582:28db:dff:fe6b:e89a"; mucbot = "fd23:42:c3d2:582:28db:dff:fe6b:e89a";
netboot = "fd23:42:c3d2:582:2:0:0:6";
radiobert = "fd23:42:c3d2:582:e65f:1ff:fe5d:1679"; radiobert = "fd23:42:c3d2:582:e65f:1ff:fe5d:1679";
radius = "fd23:42:c3d2:582:2:0:0:4"; radius = "fd23:42:c3d2:582:2:0:0:4";
sdrweb = "fd23:42:c3d2:582:3078:bbff:fe76:e9ef"; sdrweb = "fd23:42:c3d2:582:3078:bbff:fe76:e9ef";
serv-gw = "fd23:42:c3d2:582::1"; serv-gw = "fd23:42:c3d2:582::1";
spaceapi = "fd23:42:c3d2:582:1457:adff:fe93:62e9"; spaceapi = "fd23:42:c3d2:582:1457:adff:fe93:62e9";
stats = "fd23:42:c3d2:582:2:0:0:3"; stats = "fd23:42:c3d2:582:2:0:0:3";
staging-data-hoarder = "fd23:42:c3d2:582:2de:5bff:fef9:e23d"; zeit = "fd23:42:c3d2:582:2:0:0:5";
oparl = "fd23:42:c3d2:582:2de:9aff:fece:3879";
gnunet = "fd23:42:c3d2:582::44";
broker = "fd23:42:c3d2:582::46";
ftp = "fd23:42:c3d2:582::47";
network-homepage = "fd23:42:c3d2:582::2f";
owncast = "fd23:42:c3d2:582::32";
prometheus = "fd23:42:c3d2:582::4b";
buzzrelay = "fd23:42:c3d2:582::f";
oxigraph = "fd23:42:c3d2:582::4c";
luulaatsch-asterisk = "fd23:42:c3d2:582::2a";
stream = "fd23:42:c3d2:583:dc91:c7ff:fe51:d1c5";
}; };
hosts6.up4 = { hosts6.up4 = {
knot = "2a00:8180:2c00:282:cd7:56ff:fe69:6366"; bind = "2a00:8180:2c00:282:cd7:56ff:fe69:6366";
blogs = "2a00:8180:2c00:282:b8a8:7dff:fee8:5ac2"; blogs = "2a00:8180:2c00:282:b8a8:7dff:fee8:5ac2";
c3d2-web = "2a00:8180:2c00:282:642e:95ff:fe34:49f9";
dns = "2a00:8180:2c00:282:2:0:0:2"; dns = "2a00:8180:2c00:282:2:0:0:2";
dnscache = "2a00:8180:2c00:282:f096:dbff:fee8:427d"; dnscache = "2a00:8180:2c00:282:f096:dbff:fee8:427d";
gitea = "2a00:8180:2c00:282:702a:daff:fe35:83be";
grafana = "2a00:8180:2c00:282:4042:fbff:fe4b:2de8"; grafana = "2a00:8180:2c00:282:4042:fbff:fe4b:2de8";
hydra = "2a00:8180:2c00:282:e2cb:4eff:fe3b:f94b"; hydra = "2a00:8180:2c00:282:e03c:d7ff:fe8e:fe16";
jabber = "2a00:8180:2c00:282:b869:ccff:fe46:902a"; jabber = "2a00:8180:2c00:282:b869:ccff:fe46:902a";
# mail = "2a00:8180:2c00:282:88c0:41ff:fe70:d6cd"; keycloak = "2a00:8180:2c00:282:c48:bbff:fe87:721d";
logging = "2a00:8180:2c00:282:6811:edff:fe40:89c6";
mail = "2a00:8180:2c00:282:88c0:41ff:fe70:d6cd";
matemat = "2a00:8180:2c00:282:f82b:1bff:fedc:8572"; matemat = "2a00:8180:2c00:282:f82b:1bff:fedc:8572";
minetest = "2a00:8180:2c00:282:c3a:42ff:fe5d:b20c";
mobilizon = "2a00:8180:2c00:282:48d1:5cff:fea7:1676"; mobilizon = "2a00:8180:2c00:282:48d1:5cff:fea7:1676";
mongo = "2a00:8180:2c00:282:14ec:c8ff:fe0a:fc5c";
mucbot = "2a00:8180:2c00:282:28db:dff:fe6b:e89a"; mucbot = "2a00:8180:2c00:282:28db:dff:fe6b:e89a";
netboot = "2a00:8180:2c00:282:2:0:0:6";
public-access-proxy = "2a00:8180:2c00:282:1024:5fff:febd:9be7"; public-access-proxy = "2a00:8180:2c00:282:1024:5fff:febd:9be7";
radiobert = "2a00:8180:2c00:282:e65f:1ff:fe5d:1679"; radiobert = "2a00:8180:2c00:282:e65f:1ff:fe5d:1679";
radius = "2a00:8180:2c00:282:2:0:0:4"; radius = "2a00:8180:2c00:282:2:0:0:4";
scrape = "2a00:8180:2c00:282:e073:50ff:fef5:eb6e"; scrape = "2a00:8180:2c00:282:e073:50ff:fef5:eb6e";
sdrweb = "2a00:8180:2c00:282:3078:bbff:fe76:e9ef"; sdrweb = "2a00:8180:2c00:282:3078:bbff:fe76:e9ef";
serv-gw = "2a00:8180:2c00:282::1";
spaceapi = "2a00:8180:2c00:282:1457:adff:fe93:62e9"; spaceapi = "2a00:8180:2c00:282:1457:adff:fe93:62e9";
stats = "2a00:8180:2c00:282:2:0:0:3"; stats = "2a00:8180:2c00:282:2:0:0:3";
stream = "2a00:8180:2c00:282:dc91:c7ff:fe51:d1c5"; stream = "fd23:42:c3d2:583:dc91:c7ff:fe51:d1c5";
ticker = "2a00:8180:2c00:282:b407:40ff:fec1:81f2"; ticker = "2a00:8180:2c00:282:b407:40ff:fec1:81f2";
staging-data-hoarder = "2a00:8180:2c00:282:2de:5bff:fef9:e23d"; zeit = "2a00:8180:2c00:282:2:0:0:5";
oparl = "2a00:8180:2c00:282:2de:9aff:fece:3879";
serv-gw = "2a00:8180:2c00:282::1";
luulaatsch-asterisk = "2a00:8180:2c00:282::2a";
drone = "2a00:8180:2c00:282::2b";
pretalx = "2a00:8180:2c00:282::2c";
matrix = "2a00:8180:2c00:282::2d";
activity-relay = "2a00:8180:2c00:282::2e";
network-homepage = "2a00:8180:2c00:282::2f";
vaultwarden = "2a00:8180:2c00:282::31";
owncast = "2a00:8180:2c00:282::32";
mediawiki = "2a00:8180:2c00:282::43";
gnunet = "2a00:8180:2c00:282::44";
data-hoarder = "2a00:8180:2c00:282::45";
broker = "2a00:8180:2c00:282::46";
ftp = "2a00:8180:2c00:282::47";
auth = "2a00:8180:2c00:282::48";
dresden-zone = "2a00:8180:2c00:282::49";
prometheus = "2a00:8180:2c00:282::4b";
oxigraph = "2a00:8180:2c00:282::4c";
hedgedoc = "2a00:8180:2c00:282::6";
buzzrelay = "2a00:8180:2c00:282::f";
}; };
}; };
@ -160,6 +147,9 @@
dnscache = makeContainer { dnscache = makeContainer {
services.dnscache.enable = true; services.dnscache.enable = true;
}; };
netboot = makeContainer {
interfaces.serv.hwaddr = "0A:14:48:01:15:01";
};
serv-gw = makeContainer { serv-gw = makeContainer {
interfaces = { interfaces = {
core = { core = {
@ -175,16 +165,10 @@
}; };
}; };
ospf.allowedUpstreams = ospf.allowedUpstreams =
[ "upstream4" "upstream3" "anon1" "freifunk" ]; [ "upstream4" "upstream1" "upstream3" "anon1" "freifunk" ];
}; };
stats = makeContainer { stats = makeContainer {
interfaces.serv.hwaddr = "0A:14:48:01:15:00"; interfaces.serv.hwaddr = "0A:14:48:01:15:00";
}; };
hydra = {
role = "client";
model = "nixos";
interfaces.serv.type = "phys";
};
}; };
} }

View File

@ -2,10 +2,153 @@
let let
servHosts = config.site.net.serv.hosts4; servHosts = config.site.net.serv.hosts4;
inherit (config.site.net.c3d2.hosts4) dn42; inherit (config.site.net.c3d2.hosts4) dn42;
inherit (config.site.net.flpk.hosts4) c3d2-web;
in in
{ {
site.hosts = { site.hosts = {
upstream1 = {
forwardPorts = [
{
destination = "${servHosts.public-access-proxy}:80";
proto = "tcp";
reflect = true;
sourcePort = 80;
}
{
destination = "${servHosts.public-access-proxy}:443";
proto = "tcp";
reflect = true;
sourcePort = 443;
}
{
destination = dn42;
proto = "udp";
reflect = true;
sourcePort = 2325;
}
{
destination = dn42;
proto = "udp";
reflect = true;
sourcePort = 2399;
}
{
destination = dn42;
proto = "udp";
reflect = true;
sourcePort = 2327;
}
{
destination = dn42;
proto = "udp";
reflect = true;
sourcePort = 2338;
}
{
destination = dn42;
proto = "udp";
reflect = true;
sourcePort = 2339;
}
{
destination = dn42;
proto = "udp";
reflect = true;
sourcePort = 40533;
}
{
destination = dn42;
proto = "udp";
reflect = true;
sourcePort = 61699;
}
{
destination = "172.20.74.210:22";
proto = "tcp";
reflect = true;
sourcePort = 2222;
}
{
destination = "172.20.74.210:443";
proto = "tcp";
reflect = true;
sourcePort = 8443;
}
{
destination = "172.20.73.47:22";
proto = "tcp";
reflect = true;
sourcePort = 2223;
}
{
destination = "172.20.73.48:30000";
proto = "udp";
reflect = true;
sourcePort = 30000;
}
];
interfaces = {
core = {
hwaddr = "0A:14:48:01:26:00";
type = "veth";
};
up1 = {
hwaddr = "00:23:74:D7:2D:7C";
type = "veth";
upstream = {
link = null;
noNat = { subnets6 = [ "2a02:8106:208:5200::/56" ]; };
provider = "vodafone";
staticIpv4Address = "24.134.104.53";
upBandwidth = 52500;
};
};
};
ospf.upstreamInstance = 3;
role = "container";
};
upstream2 = {
forwardPorts = [
{
destination = "172.20.75.9:1194";
proto = "udp";
reflect = true;
sourcePort = 1194;
}
{
destination = "172.20.74.210:22";
proto = "tcp";
reflect = true;
sourcePort = 2222;
}
{
destination = "172.20.74.210:443";
proto = "tcp";
reflect = true;
sourcePort = 8443;
}
];
interfaces = {
core = {
hwaddr = "0A:14:48:01:27:00";
type = "veth";
};
up2 = {
hwaddr = "00:23:74:D7:42:7C";
type = "veth";
upstream = {
link = null;
noNat = { subnets6 = [ "2a02:8106:208:e900::/56" ]; };
provider = "vodafone";
staticIpv4Address = null;
upBandwidth = 52500;
};
};
};
ospf.upstreamInstance = 4;
role = "container";
};
upstream3 = { upstream3 = {
interfaces = { interfaces = {
core = { core = {
@ -28,191 +171,203 @@ in
role = "container"; role = "container";
}; };
upstream4 = rec { upstream4 = {
forwardPorts = [ forwardPorts = [
{ # http {
destination = servHosts.public-access-proxy; destination = "172.20.73.45";
proto = "tcp"; proto = "tcp";
reflect = true;
sourcePort = 80; sourcePort = 80;
} }
{ # https {
destination = servHosts.public-access-proxy; destination = "172.20.73.45";
proto = "tcp"; proto = "tcp";
reflect = true;
sourcePort = 443; sourcePort = 443;
} }
{ # gemini
destination = "${c3d2-web}:1965";
proto = "tcp";
sourcePort = 1965;
}
{ {
destination = servHosts.knot; destination = "172.20.73.61";
proto = "tcp"; proto = "tcp";
reflect = false;
sourcePort = 53; sourcePort = 53;
} }
{ {
destination = servHosts.knot; destination = "172.20.73.61";
proto = "udp"; proto = "udp";
reflect = false;
sourcePort = 53; sourcePort = 53;
} }
{ {
destination = dn42; destination = dn42;
proto = "udp"; proto = "udp";
reflect = true;
sourcePort = 2325; sourcePort = 2325;
} }
{ {
destination = dn42; destination = dn42;
proto = "udp"; proto = "udp";
sourcePort = 2327; reflect = true;
}
{
destination = dn42;
proto = "udp";
sourcePort = 2337;
}
{
destination = dn42;
proto = "udp";
sourcePort = 2338;
}
{
destination = dn42;
proto = "udp";
sourcePort = 2339;
}
{
destination = dn42;
proto = "udp";
sourcePort = 2340;
}
{
destination = dn42;
proto = "udp";
sourcePort = 2342;
}
{
destination = dn42;
proto = "udp";
sourcePort = 2399; sourcePort = 2399;
} }
{ {
destination = dn42; destination = dn42;
proto = "udp"; proto = "udp";
sourcePort = 24699; reflect = true;
sourcePort = 2327;
} }
{ {
destination = dn42; destination = dn42;
proto = "udp"; proto = "udp";
sourcePort = 64699; reflect = true;
sourcePort = 2338;
}
{
destination = dn42;
proto = "udp";
reflect = true;
sourcePort = 2339;
}
{
destination = dn42;
proto = "udp";
reflect = true;
sourcePort = 40533;
}
{
destination = dn42;
proto = "udp";
reflect = true;
sourcePort = 61699;
}
{
destination = "${servHosts.leonos}:22";
proto = "tcp";
reflect = true;
sourcePort = 2223;
}
{
destination = servHosts.minetest;
proto = "udp";
reflect = true;
sourcePort = 30000;
} }
# ? # ?
{ {
destination = "172.22.99.175:22"; destination = "172.22.99.175:22";
proto = "tcp"; proto = "tcp";
reflect = true;
sourcePort = 2224; sourcePort = 2224;
} }
{ {
destination = servHosts.gitea; destination = servHosts.gitea;
proto = "tcp"; proto = "tcp";
reflect = true;
sourcePort = 22; sourcePort = 22;
} }
{ {
destination = servHosts.jabber; destination = servHosts.jabber;
proto = "tcp"; proto = "tcp";
reflect = true;
sourcePort = 5222; sourcePort = 5222;
} }
{ {
destination = servHosts.jabber; destination = servHosts.jabber;
proto = "tcp"; proto = "tcp";
reflect = true;
sourcePort = 5223; sourcePort = 5223;
} }
{ {
destination = servHosts.jabber; destination = servHosts.jabber;
proto = "tcp"; proto = "tcp";
reflect = true;
sourcePort = 5269; sourcePort = 5269;
} }
{ {
destination = servHosts.jabber; destination = servHosts.jabber;
proto = "tcp"; proto = "tcp";
reflect = true;
sourcePort = 3478; sourcePort = 3478;
} }
{ {
destination = servHosts.jabber; destination = servHosts.jabber;
proto = "tcp"; proto = "tcp";
reflect = true;
sourcePort = 3479; sourcePort = 3479;
} }
{ {
destination = servHosts.jabber; destination = servHosts.jabber;
proto = "udp"; proto = "udp";
reflect = true;
sourcePort = 3478; sourcePort = 3478;
} }
{ {
destination = servHosts.jabber; destination = servHosts.jabber;
proto = "udp"; proto = "udp";
reflect = true;
sourcePort = 3479; sourcePort = 3479;
} }
# leon's vps1
{
destination = "${servHosts.vps1}:22";
proto = "tcp";
reflect = true;
sourcePort = 2225;
}
{
destination = servHosts.mail;
proto = "tcp";
reflect = true;
sourcePort = 25;
}
{
destination = servHosts.mail;
proto = "tcp";
reflect = true;
sourcePort = 465;
}
{
destination = servHosts.mail;
proto = "tcp";
reflect = true;
sourcePort = 587;
}
{
destination = servHosts.mail;
proto = "tcp";
reflect = true;
sourcePort = 110;
}
{
destination = servHosts.mail;
proto = "tcp";
reflect = true;
sourcePort = 143;
}
{
destination = servHosts.mail;
proto = "tcp";
reflect = true;
sourcePort = 993;
}
{
destination = servHosts.mail;
proto = "tcp";
reflect = true;
sourcePort = 995;
}
# poelzi # poelzi
{ {
destination = "172.20.73.162:22"; destination = "172.20.73.162:22";
proto = "tcp"; proto = "tcp";
reflect = true;
sourcePort = 2323; sourcePort = 2323;
} }
# jan
{
destination = "172.20.75.3:51820";
proto = "udp";
sourcePort = 30057;
}
# zw-ev RDP # zw-ev RDP
{ {
destination = "172.20.75.222:3389"; destination = "172.20.75.222:3389";
proto = "tcp"; proto = "tcp";
sourcePort = 45000;
}
{
destination = config.site.net.core.hosts4.vpn-gw;
proto = "udp";
sourcePort = config.site.vpn.wireguard.port;
reflect = true; reflect = true;
} sourcePort = 45000;
{
destination = servHosts.gnunet;
proto = "tcp";
sourcePort = 2086;
}
# dresden zone
{
destination = servHosts.dresden-zone;
proto = "udp";
sourcePort = 51844;
}
# data-hoarder
{
destination = servHosts.data-hoarder;
proto = "udp";
sourcePort = 51820;
}
{
destination = "${servHosts.data-hoarder}:22";
proto = "tcp";
sourcePort = 2269;
}
# data-hoarder-staging
{
destination = "${servHosts.staging-data-hoarder}:51820";
proto = "udp";
sourcePort = 51821;
}
{
destination = "${servHosts.ftp}:22";
proto = "tcp";
sourcePort = 1022;
}
# coloRadio
{
proto = "tcp";
sourcePort = 8000;
destination = "192.168.9.127";
} }
]; ];
interfaces = { interfaces = {
@ -238,12 +393,7 @@ in
}; };
}; };
}; };
ospf = { ospf.upstreamInstance = 8;
upstreamInstance = 8;
stubNets4 = [
"${interfaces.up4-pppoe.upstream.staticIpv4Address}/32"
];
};
role = "container"; role = "container";
}; };
@ -264,7 +414,7 @@ in
}; };
}; };
ospf = { ospf = {
allowedUpstreams = [ "upstream3" "upstream4" "freifunk" ]; allowedUpstreams = [ "upstream1" "upstream3" "upstream4" "freifunk" ];
upstreamInstance = 5; upstreamInstance = 5;
}; };
role = "container"; role = "container";

View File

@ -1,40 +0,0 @@
{ ... }:
{
site.net.vpn = {
vlan = null;
domainName = "core.zentralwerk.org";
ipv6Router = "vpn-gw";
hosts4 = {
vpn-gw = "172.20.76.225";
};
hosts6 = {
dn42 = {
vpn-gw = "fd23:42:c3d2:585::1";
};
up4 = {
vpn-gw = "2a00:8180:2c00:285::1";
};
};
subnet4 = "172.20.76.224/28";
subnets6 = {
dn42 = "fd23:42:c3d2:585::/64";
up4 = "2a00:8180:2c00:285::/64";
};
};
site.hosts.vpn-gw = {
role = "container";
interfaces = {
core = {
hwaddr = "0A:14:42:01:26:01";
type = "veth";
};
vpn = {
type = "wireguard";
};
};
ospf = {
allowedUpstreams = [ "flpk-gw" "anon1" "freifunk" ];
};
};
}

18
config/net/yggdrasil.nix Normal file
View File

@ -0,0 +1,18 @@
{
site.hosts.yggdrasil = {
role = "container";
interfaces = {
core = {
hwaddr = "0A:14:48:01:26:ff";
type = "veth";
};
};
ospf = {
allowedUpstreams =
[ "upstream3" "upstream1" "upstream4" "anon1" "freifunk" ];
stubNets6 = [ "200::/7" ];
};
services.yggdrasil.enable = true;
};
}

View File

@ -1,85 +1,62 @@
-----BEGIN PGP MESSAGE----- -----BEGIN PGP MESSAGE-----
hQEMA2PKcvDMvlKLAQgAjGer7r8wCoigtDTS5zzUnJI02b3RQvhbqjv4a6RD52ry hQEMA2PKcvDMvlKLAQf/VrM3oRXn8dHbFyxWAps/OAhk83HD4RCIlSQUcEHYHi9i
NzqqX7yIVyOEP2SnqoBpmWHYFJ3WcRb5Io3DXBLjgVHZbWJMP/DtVzHN+1ix3A5T hMr44NqNVms4/E02bWMKlkUZmeEaVo92QmTUYyDF8hZUgZ59Kh0gQoXbSukA+8Kn
ZjxROLc/EDyd+prSvbol5UJkHJeoH7PWwPmO1VPOVZwAV+NGJS/qKXz/wUGFA6y5 lJ0HWg3HuAr/XqCDm3AWBzHAhuL8rYg8tKxwbvKNjk5uKd3VhpyEHYapBKmPgP5D
iH6vzetTvxSBt08dYVulzmI/B6MwHUz8W7YTTal7QTKftlyzXWZHydbj1AWJjGoR yeP+OoMwHxm9ltCrNKehWJavGpI0NolcLqoaOVrltwwlLCC6cWxH0SWnM1NUigJ5
qadxsH4ZlqdHJrP/j5Yvw72XgdzAN7MQrofslqFI9ro9nccLQ7Q3B7kzt/EvoOPm 3FfakgI2uD4wsfUB2DsIfP5rraCmC/K7PFSRxJ8z4LRDAG1WNxK7CA9oYFSqEIo7
obPHW1I0UFoFXhfTujROXwVlernk6qmxO/oNr5UZB9LqAaroXhliddAzPZPT5qcK axMDZvRfFViqs1grXruTQzI2GAodvMt4Sqw9TXGi4tLrAU8a+GvXDcoIYHe2MmUP
szctWSv1eNlGO44iwIJyrh/Yetmrhll8flPl9URWIi9r383xkawhxG52alUVjRIz dxN/tq8nJUE+PEq6RtdIcuOv1yhkgXHAfzcf7gWIugREglGywfX0Ops9+Mp8UQnz
u2BC3vdrt5o0GfEpZlDo23UbIxLIFbMg2xTXcFBq5TJEw0+owwhz+m+JRrXY9h1+ kRbPI4m7zkzIozsq0Q7CSrKVAwT/CC+gpMFtOx+uZOPC02p4za6yL5GMgPBKHmr8
SVlMX0PcUUg4vmX+7/KVIwrSECFpfPcBTSyMafUT6SfxG02/WmvzcEXk8E8hK+a3 qbMujryv30Ua48SeVRhgI+ScnUxXBau6VGWOPX4U7v6Y5jtJkea9lFHurNpByAaf
VzolJIqirrv1CRwm60xOucytFI5OnxYI3kV9saiLwB6i9KI8Hw91pM7T+kQmXbbl 4y12GFlePqbcVrGdcfCL15fDkhfi5ba1nlpi+dILJYegttis5iNMyueKb2jDzFjk
etRddcQLXdhjRB/bCUJbQeEKZx0gjVAQkTFtdz6tp2vc9u/WS6UMrrQIkzdwLIOg vpY9PG0Npxa9YCq1IPawTEwU4/sFh00psM9jdXBNne33FNyYcpy+gF0+fCU6Y0o6
AXa8JmCtlTcN1uVVDlmQqba5li6ObqM4dtyOwHkXmpwBLObtoSg2yxTExxVwtAxz qXB2V1iSaVLxW1te5UQV2rn0QAKwpbE+c7IL2oEizktBzNEDB94ls0hdzo8j1Umd
CgNcPZ9snnht8MpXGrrzQUsdGfBY4gZ8Hgh1oScqW9b8o5XtT74hdtWXFMv6tE2F wCk6x7UGU0iJCZtg/a6THmDEoa7ib7U4qeBB8XoJYW6VA113ROc+VFbdl1aDyA3o
8bco4QBt6q95aYSi/wcyLwIyhUI+PEh2m5UM7KjYs2xxWbzU7Q0nj70VI9x+0Y+U jCB5zQR0/RI+xrvc9Vn57bmlrOsTVkG0kf17a3MWVfYobpHCg2OBTLlaGEfvdcZ1
Apez4mYlqiep5l94E4Q4wb3rizYeXFAzZDe5FXfcpRgVPHGSq6XWUYSgyQENuRTB EwMGTJhnakJIkbKJdO1b2ljp6NaJMxJdQLVHjyFB6JjDRosZPeW4qO5jRgShMaVL
Ll8usdYLgT3Y7ULxT4O/8OKkDFMyfmTIdSiJRUJ8izMTm0yq5lKrSsqYTZVNOF6v 4ZZb3XORms679ItX19DanCEP2ouo8MP9Fbt3y6C/s0YqOOAOOa5o4Wb04098Upod
NDEolddj4DOaRV07DkrQRMpukrTCauZdC/c/hwmr3+ZcaMi33ZKHIbCXex/34D9z 7TH70faAtzgcx9nZ4aoPsXWgbvoEGWyJZvoRxF/6X887z+cLYtY+6K709TSsYc+F
0CH3fA0nn/w3jh9CwOKBrT+cbOlMF3gVJbQU8xGgf7QHyaf8dEoayiInk9wKfUJd 3TGt8gpt+kzfwuGv9QUQ/tDAdvR3LPQ4zKJ4COJ89ybuop4+GlrQC2v/FvE58LJ+
BQ6YGukQBb6KDDNuDq0r9UYeRPjWc/mGSZkluoEl1GVFkFNpxlKStB68hNRJg63i q1yS/kim+/FsvmwAM+7vYj/wn6hXAWn2rleWTcFgmu4MwIyxfwjUcTXRrUptvnRS
gS/l6jSkj1IKmsnbkJVtC+YwH/Pkx6+fcisXmUGPZ9KUiw2qiCGLFbHm5Shc7YBW juY71sqQMe/44QB2KZNDvNX6efj2ay0Uvx6MXBN2Wfkn0lFrlspcgP1eDdQZDgDU
BpiZzCEjRrp71lB5URbbY+zhf+lcAdxewbw8v0R0tJP2hzmXCqsvJnB4jcEc1YD5 HyemCXAYmylUYXVNgwENksKpaV5vbSZSuN0QHzzcpNR/ur3Jne9uPe2AqzXanep9
lFD/4ivgZ95pVaoV+WsjETZZd3pkvo2PQC0f/2momT+KwYAdwcPfwJH8S9FLBjKE ozQoz7YCOlXxqqWzI2dV0JqszoLQA0OarFlGAmR1eA2tfxnUayMjHl85LEk2PGI6
nQRlYRjiUUEMO7TZ9J7a8onyFxozVwH7IJMz/L2wEs0u8dPr3Rj3kpCbHD8tNCE4 IMyKIyB28tkue1ualu/deq+3CHBdJmWLUeC7DSSUH8NLzChcnJDZA+Vyiic4Ovdr
BP5s1d+S18vSKNRBYY2z7t1eyBZ+9hu1vgWR7GsAcgwCv6YTfVT8VE9RBdkglwP2 N+hTeUQM6BHIGNtgX7LtH+2phdA4Mc9Vl2b7AtDghZmz5IcBA90G8PVkhSBY0I/j
Me6G1Af5KMNyQq0GDaKT/pPlS3WCdjpkOHCpw+2HfSjPVDAvWbBkrB8xQrQp8kwg ssphtIroQwfC9Z8vQmmQkwAv/VgHIstp8UM51K1c24ckCFduu2Vo6SOaDUwV2efF
mHMD9udGsfpUSQVoNxIjIeK9EfFEjgXA+53/BVuCbSL5bWQXnKCMba656z7UrWqo x/F4RPHr/A2TzdAZj3cIe5S4Gkc9D/5p8PJ2w2MuP+fKWTE9Z3IM7BlbO6VlLbxq
NqVdJ7c8N7/U9fxaUaagDoziBUsV+eT58eGFRZJJHkbDZvmRthYOQnR82KSQz2cx VZTIzjtivJKaD7B0hpyWcjqI6GU3o3FvMyOLCFTJvrXpWfCAErsHf1I8vtPI2T7I
Neo9z3mSVA8FVRnwNaSNZiHRRKoFY+6HfDOmP5PzAIrW1/TBVYR6+5gmqou3KPqY eBYl85LNOiqPTDkjqQHFe/BahPzNS8c1tdfdCmY1ILRdYCN2DM9RVZmbyypyt49z
1I8DKkVYqlRSve+GXeFIEkeiJ8N5BZ4WZw3EglWSrP+uG7zywJ1pWNja5WNKSzX4 K3IHMi3G4RizGXQ+tdfmsqO/n7TInY9p3td2RcYcUT1AfQOkiMV9jBrBuylPcsvh
mXPdI6KxTL40V06SraUqAOhd8uqH4fEhaBJVCqtm9cdXar7dqAbkaX5RARDb/BNg q7AlmlIEPikhlXCxFIkt/zQPy6qyka2GS1n5yl0MyqE40e5pSZkkvBN1dt6+Kvxw
K4m8iDRkrFCO6JYMmwWJz+q/HxY5u71szxFKUiYREeP0udxapekx6IELMwnMrdUT EIUyxRPlFjoQXtDgtAA8vEgl5feNkD1QviM+72dvPOo4lszHLHxdI87hqYCysRCA
GCryJs0VJuRDsOxSyuGprz+UnhY/K7NXRmE6hIrXJQ5mjsHtyjd2vk+OzJY6mL7S XGaCa/qExxuG0Hl+6X7iI9adGlFz9iiQrVYjZoGOXC2z7Vkd8Dr4LY2xSyVHZDaQ
vRZw5FUqRvFsXXLNq/+YtRZSSZChMX0BM42prcC61PIm8qiVLs2199hKWmJmBill W4h7PJ5OPGKhwUY9V8ZDgSdiwLa0Bgoc+fSf/mDZhzOjV34tDh8G4gU3GaZGjG4Z
DZnTJzvm38EWBPkm5JGh4tJ9VN769kyhDtWKtZ4aEuykcPJor+Did+oYuMadKUCN 8J2Hj1H4At4McETx+Tg5aqJfFM71EG8no5PNBaKXQ5lInMR5dFh+OUVizGmLDQmi
0NAuKxXAUHc/TfnSxBZxRdHWZo9vyYhiIWNoy5724yWfBH+STgNy3c+Z/JeKXvVB a2aK6SzvwEegijKQWMyHTvPEzJAg/mghM2s1EN4kg12VvO9LEMC7F65YWkpGktg3
YUM4J7ys2TEnTmcoR43MPrF2+bdDsgsItQjtLlBmRvRItdswFYkunuQRBYmXoNBb Zch0J4b5z+QMMDOC/gAkYfalRvraV6rDRzhbrLsQe870zqvdyArurHbmpBpvE1Sv
2MTTxHSU4jyM5FUxBi9XAk0mnWgo/aK/FhfE73VxvVXwfwpEkomL/TFexGzfFx7d sDgcYKWwZ4w8gcxaju4qk9NNkFkPaZP/Cz346HWUDWPr8SbZGZ3O7WNm0JvFy9oS
70T8RWCYgFHOuoe+O04wo2qyvCZZittRQGlInNztDCQI6lqa8TSILVgIRMgvnrcR HwOm32yc8RT2dfzRIj4faGMrGUsXG5dULoyrYfatxDM3ohMt8BvvqJ8i2EVHpZI2
P9BUixDlFfl8x4g0lacxZm9nN5XNgnI1RTiXNXeigIciRydyeAKoV3gxY54i5jOm ZElpBo7qM08+9VpwBpBseBxjE3uAkqBAaBBwRfecJvQuFjgQowk8uOmhGvvPQ+v3
VFUClFfQFz+nBStRQumqxMXKa433J1l8NENmZmkc+D2TeLt8kbgNN4Zg7zKiNRFt lcTIErizNHDyKhbwMvzURNELa6TqThaeHQi3X9djiSvl+uUgu1nGnCZwK/ApYa0a
UvFEtqPxQSiFgLCjrMH2wLkq79EtP/Zfpok/1iGbKfT+/bhDFB0iWE0AdIAa0oiu Z0BvM7sap63DTdete3iWo/OKKTL+yU6QpmV69wUNmVn867E+naX7GeqgMS2PcwdI
1JDsSFmoMTtMHgywSvVxaDVE4/0C81D3foLERbc+dwo00+YyROrQ74+mNoFrY4vd kFmWFzKf4m4BpodfJ8II0M3tE3nWYwGRKy72DjrP1TittRyhTIRMKh0N4jnYlh+g
xcDKxgkcZeZXxsUlox0F26OVZ3B7krUQC7EbBBVvdimJk7S0WXTHfR5ENz7lp1C2 TeTodvcZL5xL2lwLvxBbULtz0wRVcloB1BPla2LiBlclpdKvKmgRk36gvq3E5N6/
2gRL8Pdj9I4VsOmGAfcNPV2J5RVdRwyL9dSxCPVQ4ECrBqHSPqGbQoT7aHX9b+6A CJ+BQ94QjLa1EcEBjYtK557nyFW2s3Km8tD1+FAO+uj2X9BLq9Qyax/FMteiSwF5
LKCWUqC18NxrRr4dbSxcjkE4w+vPmENrDh+yR7zDgdWY03rGN/jT2CV1le69AAaq rPEfy9OhZH2v2jkYCfc9scFA69PkskfJQ6ZfnJT4mYMmn1UEN3L+Q2b66hdaeIbo
RTf5n+skzsWz+u09bW7b43gpwhh7YeSFKpogNZ8z2ujEr0fkrGsOWWba9z620Xls SmH7Es9xofBN+2MYOYPTg5ptyYUAlLVdnJrgAnKIylPr3iedBLJ2mYK6aDoj3PWT
f/4dPKcNiJLOIOXT555xZSpsgzAtPO1g9QM+l8Q6PZjqAvGjbHsYMw5ao+iwL0qt 7klVaCJfxNxb7siiwKJjTvs7Y/7eI1mN5dsPW0OWCWONzR+XGu4wwT+CcZURB086
M93Uj47PxD4qqz4MwYQw8S/dtrUkvBDEoA2fVU/00Fb9XzrECDUffDxHEUmDIcJQ yD4DyFOpZb42RN8NBTwyiKOYVsd/7jUKXat0HQswRy7hDW3qs5aIkLJCaX1vd9an
h/q7ZntcVp//Gy4DeEiqp63s6poWGdbDmccN3hWmzWHEI0HR7pNS/FHEzESCw9oh 56b1Fwu9FMhIzEdLPPrJQMLA3xYDh4NiOwO0oy370Pdoy1aPa6lMA7QrQrZXfpsz
PkZzOa76GmyDqbopneVUmtfCuBjahTjVSAv4YlAsqQMI5wUgV+bwlfB7Rm2v8X4R eFpgRSEkzJFlDRTSYsdczx3Kdpe8L9Ha3KJ3m261mQIUucnIFQlES1tfv2au87x6
cyka3F9xWxuC3/5vxuPyyxA1YZc/fzpOqafFCU3mGF2byOKCL0YNuoqUbQBtagHZ 48dZRT8EyAoTQiCH8e7sRpZUYllgM71peyQNWSnqoNERp9PL3eRTWzfa9xn9IglD
6rrmGqNjyVuUG15KLBF29sYlJTBYF7tAeyVx2vLJqzKPRMGL2Ph8wg8Rg58eqKgU CyuSAuRgivvSanVqNOX3xFQ1doAT4mfJ2HyA1IZOPXOxSGiueyAAOeUbQOsl7xHv
gUIlCGzxGoqK1fVlrvvRATHplO77s+W/dA0svfSeD3xrtEd5oF9oQeI78A71Vmrw 7L7UdvHpVta2Rn1I8kuPrvAGiFkM5ROyMF6bBqkwu+cZ+oNdP8xwZ6ovxOBNeAwV
ZsMech54mketddbn9t2MID8rVWxTtX5xIAxnW5TBfO8DucsqbxsJNm7Edzue0C2L Fx/ZEJZpnU2BAjkZrHA/OLJ7sgFo+Pqo0BpnDaZVO0xtVLYHUMBTqt4uGaHJ/qIJ
i7tDKM5ZSbkivh0C7G1w7cu9SAv7gHStu+3DKGlW7MmCfLSEGk34jRdTRUu/2KAh 3KPJDjHq1CRyLFwQ+HKT3QYu9IsvJ33PQGwFcqP8pyuhXX0z3QaLUs9tZ93jW4d3
cbHxHj25mDC6ZPz54FX6iDA0epm0ILVXZa75gjlfq4o9ldjKbR6yueIuc2hy7H1b 70XDQ0udMjazKHQnpLpqleVqvG6vDI5KcXRn8GzMyDHsSObak+pKNIm01TjYmDEj
QFlmx415H5TGTpjSJdjXCqvbbwphOIqsN0Qh3ZqUdaboVGipZdlFv3FH/2uxAFKW cDk7a+5d5DNA4ELExj0Py/C3D8JtcQzycnZv6EwGsyLsDTtQhSkGHcvfK6u0SfvD
VMJ1CpFAWe2iLtQEgrxJ15xpsLx+zcFUfftR8vXNRwMcEffV7xQguTugGic5O0DB aWg=
m5Oopo6bB9wMU4tvDRosjnvMEkuwbSPLSA/8JeZFO1zCK8Pa2znYNEwHNxeHiTCT =2R32
+oouXDqdcT9dnH4cg4GeHjVDZO0I9yZL/cMDUPtqN0XySXe8Zj7VxtpQmcePklV/
RDoGKHxEVz2a16foONjtVfsoheFHLWAI47IOTFDHA/CSQLCmCqwpfZQIuX2oWRwc
aPN4t5Qkx5TllLzL6keXkDV43/yw0dnXBQQDQ/Z4DP5GShwahyFggA/XonKYb9F0
B+pz+NOOkZjcFrcFeMr4cMdffc2ACxDJZWH4BHcwM9WICqoefJHlUu65ZTBBlisJ
mwP4Xapx8khsln2xXDUfhsoXu5+FHBexyVP1OUmZZ+zO3UEXPa+OwpglqrYGMueE
iXEO2lCOi6HrQCd7cvONPEwLaqavojMhsP42ywirWK7J9XuCoaEWtZjlA/Sq2D2B
upK6WuFMr+eE5lhrp5LFCRMJoiiwJb/bA7sMdZhg6HjIZNoNkrCvdgvLScbKxHM8
4G82FAafs/fbel5mdUNEe3nOXhQX2KH1MkUhnKGv5hi9gsXLaJlQTZBFsjoT8MUX
XUNdEWQ/xtGjs7eNBn/MzpP3JeByrDG0u0Tbt2whOkwhKQt+odph7sMRxwtvvniu
ij9nA3OlSGpTEItmC1jls29sJy5/0Ojp6Y3v/ZBfG6xh0xhhjpZIoOGQoK1wdG4m
m0j6TZqRKwX9FqQ9aCVY65lp/MsdXehe6/EShyT4K56KuGbpDuzoeZRshDPOvcjU
A1t44vBp3aYH9gE6QfM/dg8akN+LXOM7komveAbFvcvE8KFVdfHOUJIjPyy+saX0
ZHWLrH/SU+vUuFUw9VSuEavar95l9pRyWCeV67DWN2+FY8HESlfltjwiswActvrt
uDeIdtd42y4yA5u3BFCGEAWgZm+aVkQxuMN4OynTHM3NGJ6NUOeL8cGMA02KE65v
8pg4o3sIjfmsD76srDx7hKIpIe+K4QpAIxxL21HPZuXhE3ksNHh3x5x7hjkvNAUi
z3xbaR03avMeSle1LvUH/A88Fn+/0ataHYiQiIM95RXvMdKAk6SNNsN7rp1RZNhV
X6cNTBz2uUVbAXMUgbbBc9O2AVMR0pbfAYBKHPm24b+tWMShG/DR9f/mFFdUznEX
9+ydjRh9Mh9ZYgzKXqA9SZ/4Zhqn2Mve3r3Rii4K2w6KUbxRHev7FpV/KGgYsMmw
bLjSgS/cwQ7Ky9yRM12EmoAcimy/7vpyPRBM1tWnPBKhZf1xq15UM/lf53OcBjxb
ezeETqSQc6flKtEAxRv6nWSuormgn6JbClMjhII3velUKyfPCe29HNtFQ3LWJu4R
WLMH7A2qx0cIuyOuoFXefWh/9C3fiO72hqI5yQ2x4dxtEutUNTmByxZxTxJD/tSN
BI3ZmHeysFpUVdfDdt3Nc/Jw3lQCuBk=
=sq5B
-----END PGP MESSAGE----- -----END PGP MESSAGE-----

View File

@ -2,8 +2,6 @@
{ {
site.net = { site.net = {
core.ospf.secret = "encrypted"; core.ospf.secret = "encrypted";
pub.wifi.ieee80211rKey = "2dc40abba46da9490ea0e00f93f18ce5";
c3d2.wifi.ieee80211rKey = "d1b1fa2461efc0df9e2d96579607b7f6";
}; };
site.hosts = { site.hosts = {
@ -45,6 +43,7 @@
ap40.password = "encrypted"; ap40.password = "encrypted";
ap41.password = "encrypted"; ap41.password = "encrypted";
ap42.password = "encrypted"; ap42.password = "encrypted";
ap43.password = "encrypted";
ap44.password = "encrypted"; ap44.password = "encrypted";
ap45.password = "encrypted"; ap45.password = "encrypted";
ap46.password = "encrypted"; ap46.password = "encrypted";
@ -58,33 +57,13 @@
ap54.password = "encrypted"; ap54.password = "encrypted";
ap55.password = "encrypted"; ap55.password = "encrypted";
ap56.password = "encrypted"; ap56.password = "encrypted";
ap57.password = "encrypted";
ap58.password = "encrypted";
ap59.password = "encrypted";
ap60.password = "encrypted";
ap61.password = "encrypted";
ap63.password = "encrypted";
ap64.password = "encrypted";
ap65.password = "encrypted";
ap66.password = "encrypted";
ap67.password = "encrypted";
ap68.password = "encrypted";
ap69.password = "encrypted";
ap70.password = "encrypted";
ap71.password = "encrypted";
ap72.password = "encrypted";
ap73.password = "encrypted";
switch-a1.password = "encrypted"; switch-a1.password = "encrypted";
switch-b1.password = "encrypted"; switch-b1.password = "encrypted";
switch-b2.password = "encrypted"; switch-b2.password = "encrypted";
switch-b3.password = "encrypted";
switch-c1.password = "encrypted"; switch-c1.password = "encrypted";
switch-c3d2-main.password = "encrypted"; switch-c3d2-main.password = "encrypted";
switch-d1.password = "encrypted"; switch-d1.password = "encrypted";
switch-dach.password = "encrypted"; switch-dach.password = "encrypted";
switch-ds1.password = "encrypted";
switch-ds2.password = "encrypted";
switch-ds3.password = "encrypted";
upstream4.interfaces.up4-pppoe.upstream = { upstream4.interfaces.up4-pppoe.upstream = {
user = "encrypted"; user = "encrypted";
@ -97,75 +76,75 @@
privateKey = "encrypted"; privateKey = "encrypted";
publicKey = "encrypted"; publicKey = "encrypted";
}; };
flpk-gw.interfaces.up-flpk.wireguard = {
addresses = [ "fec0::1/64" "192.168.0.1/24" ]; yggdrasil.services.yggdrasil.keys = ''
endpoint = "0.0.0.1"; {
privateKey = "encrypted"; "PublicKey": "0000000000000000000000000000000000000000000000000000000000000000",
publicKey = "encrypted"; "PrivateKey": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
}; }
'';
ap1.wifi."platform/qca953x_wmac".ssids."uebergangsnetz".psk = "encrypted"; ap1.wifi."platform/qca953x_wmac".ssids."uebergangsnetz".psk = "encrypted";
ap10.wifi."platform/qca953x_wmac".ssids = { ap10.wifi."platform/qca953x_wmac".ssids = {
"Ebs 2000".psk = "encrypted";
"iz-dresden.org".psk = "encrypted"; "iz-dresden.org".psk = "encrypted";
}; };
ap11.wifi."platform/ahb/18100000.wmac".ssids."braeunigkoschnik".psk = "encrypted"; ap11.wifi."platform/qca955x_wmac".ssids."braeunigkoschnik".psk = "encrypted";
ap12.wifi."platform/ar934x_wmac".ssids = { ap12.wifi."platform/ar934x_wmac".ssids = {
"IrèneMélix".psk = "encrypted"; "IrèneMélix".psk = "encrypted";
"paperheart".psk = "encrypted"; "paperheart".psk = "encrypted";
}; };
ap15.wifi."platform/ahb/18100000.wmac".ssids."etz250".psk = "encrypted"; ap15.wifi."platform/qca955x_wmac".ssids."etz250".psk = "encrypted";
ap17.wifi."platform/ahb/18100000.wmac".ssids = { ap17.wifi."platform/qca955x_wmac".ssids = {
"EDUB".psk = "encrypted"; "EDUB".psk = "encrypted";
"Zweitwohnsitz".psk = "encrypted"; "Zweitwohnsitz".psk = "encrypted";
"e-Stuetzpunkt".psk = "encrypted"; "e-Stuetzpunkt".psk = "encrypted";
}; };
ap18.wifi."platform/qca953x_wmac".ssids."Restaurierung Wolff/Kober".psk = "encrypted"; ap18.wifi."platform/qca953x_wmac".ssids."Restaurierung Wolff/Kober".psk = "encrypted";
ap19.wifi."platform/qca953x_wmac".ssids = { ap19.wifi."platform/qca953x_wmac".ssids = {
"Bockwurst".psk = "encrypted"; "Studio 01127".psk = "encrypted";
"Walter".psk = "encrypted"; "Walter".psk = "encrypted";
}; };
ap2.wifi = { ap2.wifi = {
"pci0000:00/0000:00:00.0".ssids."C3D2".psk = "encrypted"; "pci0000:01/0000:01:00.0".ssids."C3D2".psk = "encrypted";
"platform/ahb/18100000.wmac".ssids = { "platform/qca955x_wmac".ssids."C3D2 legacy".psk = "encrypted";
"C3D2 legacy".psk = "encrypted";
"C3D2 IoT".psk = "encrypted";
}; };
ap21.wifi = {
"pci0000:00/0000:00:00.0".ssids."ZW stage".psk = "encrypted";
"platform/qca956x_wmac".ssids."ZW stage legacy".psk = "encrypted";
}; };
ap23.wifi = { ap23.wifi = {
"pci0000:00/0000:00:00.0".ssids."LBK Network".psk = "encrypted"; "pci0000:00/0000:00:00.0".ssids."LBK Network".psk = "encrypted";
"platform/ahb/18100000.wmac".ssids."LBK Network".psk = "encrypted"; "platform/qca956x_wmac".ssids."LBK Network".psk = "encrypted";
}; };
ap24.wifi."platform/ar933x_wmac".ssids."farbwerk".psk = "encrypted"; ap24.wifi."platform/ar933x_wmac".ssids."farbwerk".psk = "encrypted";
ap25.wifi."platform/ar933x_wmac".ssids."farbwerk".psk = "encrypted"; ap25.wifi."platform/ar933x_wmac".ssids."farbwerk".psk = "encrypted";
ap26.wifi."pci0000:00/0000:00:00.0".ssids."Dezember".psk = "encrypted"; ap26.wifi."pci0000:00/0000:00:00.0".ssids."Dezember".psk = "encrypted";
ap29.wifi = { ap29.wifi = {
"pci0000:00/0000:00:00.0".ssids."jungnickel-fotografie".psk = "encrypted"; "pci0000:00/0000:00:00.0".ssids."jungnickel-fotografie".psk = "encrypted";
"platform/ahb/18100000.wmac".ssids."jungnickel-fotografie".psk = "encrypted"; "platform/qca956x_wmac".ssids."jungnickel-fotografie".psk = "encrypted";
}; };
ap3.wifi = { ap3.wifi = {
"pci0000:00/0000:00:00.0".ssids."C3D2".psk = "encrypted"; "pci0000:00/0000:00:00.0".ssids."C3D2".psk = "encrypted";
"platform/ar934x_wmac".ssids."C3D2 legacy".psk = "encrypted"; "platform/ar934x_wmac".ssids."C3D2 legacy".psk = "encrypted";
}; };
ap30.wifi."platform/ahb/18100000.wmac".ssids."WLANb0402".psk = "encrypted"; ap30.wifi."platform/qca956x_wmac".ssids."WLANb0402".psk = "encrypted";
ap31.wifi = { ap31.wifi = {
"pci0000:00/0000:00:00.0".ssids."C3D2".psk = "encrypted"; "pci0000:00/0000:00:00.0".ssids."C3D2".psk = "encrypted";
"platform/ahb/18100000.wmac".ssids = { "platform/qca956x_wmac".ssids = {
"C3D2 legacy" = { "psk" = "encrypted"; }; "C3D2 legacy" = { "psk" = "encrypted"; };
"C3D2 IoT" = { "psk" = "encrypted"; };
"FOTOAKADEMIEdd" = { "psk" = "encrypted"; }; "FOTOAKADEMIEdd" = { "psk" = "encrypted"; };
}; };
}; };
ap32.wifi = { ap32.wifi = {
"pci0000:00/0000:00:00.0".ssids."ZW stage".psk = "encrypted"; "pci0000:00/0000:00:00.0".ssids."ZW stage".psk = "encrypted";
"platform/ahb/18100000.wmac".ssids."ZW stage legacy".psk = "encrypted"; "platform/qca956x_wmac".ssids."ZW stage legacy".psk = "encrypted";
}; };
ap33.wifi = { ap33.wifi = {
"pci0000:00/0000:00:00.0".ssids."C3D2".psk = "encrypted"; "pci0000:00/0000:00:00.0".ssids."C3D2".psk = "encrypted";
"platform/ahb/18100000.wmac".ssids."C3D2 legacy".psk = "encrypted"; "platform/qca956x_wmac".ssids."C3D2 legacy".psk = "encrypted";
}; };
ap34.wifi."pci0000:00/0000:00:00.0".ssids."etz250".psk = "encrypted"; ap35.wifi."platform/qca956x_wmac".ssids."Koch".psk = "encrypted";
ap34.wifi."platform/ahb/18100000.wmac".ssids."etz250".psk = "encrypted";
ap35.wifi."platform/ahb/18100000.wmac".ssids."Koch".psk = "encrypted";
ap36.wifi."platform/ar933x_wmac".ssids."C3D2 legacy".psk = "encrypted"; ap36.wifi."platform/ar933x_wmac".ssids."C3D2 legacy".psk = "encrypted";
ap37.wifi = { ap37.wifi = {
"pci0000:00/0000:00:00.0".ssids."hechtfilm.de".psk = "encrypted"; "pci0000:00/0000:00:00.0".ssids."hechtfilm.de".psk = "encrypted";
@ -176,26 +155,26 @@
"ZW heinrichsgarten" = { "psk" = "encrypted"; }; "ZW heinrichsgarten" = { "psk" = "encrypted"; };
"plop" = { "psk" = "encrypted"; }; "plop" = { "psk" = "encrypted"; };
}; };
"platform/ahb/18100000.wmac".ssids = { "platform/qca956x_wmac".ssids = {
"ZW heinrichsgarten" = { "psk" = "encrypted"; }; "ZW heinrichsgarten" = { "psk" = "encrypted"; };
"plop" = { "psk" = "encrypted"; }; "plop" = { "psk" = "encrypted"; };
"millimeter" = { "psk" = "encrypted"; };
}; };
}; };
ap39.wifi."platform/10180000.wmac".ssids."EckiTino".psk = "encrypted"; ap39.wifi."platform/10180000.wmac".ssids."EckiTino".psk = "encrypted";
ap4.wifi."platform/ahb/18100000.wmac".ssids."jam-circle.de".psk = "encrypted"; ap4.wifi."platform/qca955x_wmac".ssids."jam-circle.de".psk = "encrypted";
ap40.wifi = { ap40.wifi = {
"pci0000:00/0000:00:00.0".ssids."M".psk = "encrypted"; "pci0000:00/0000:00:00.0".ssids."M".psk = "encrypted";
"platform/ahb/18100000.wmac".ssids."M legacy".psk = "encrypted"; "platform/qca956x_wmac".ssids."M legacy".psk = "encrypted";
}; };
ap41.wifi = { ap41.wifi = {
"pci0000:00/0000:00:00.0".ssids."Walter".psk = "encrypted"; "pci0000:00/0000:00:00.0".ssids."Walter".psk = "encrypted";
"platform/ahb/18100000.wmac".ssids."Walter".psk = "encrypted"; "platform/qca956x_wmac".ssids."Walter".psk = "encrypted";
}; };
ap42.wifi = { ap42.wifi = {
"pci0000:00/0000:00:00.0".ssids."jam-circle.de".psk = "encrypted"; "pci0000:00/0000:00:00.0".ssids."jam-circle.de".psk = "encrypted";
"platform/ahb/18100000.wmac".ssids."jam-circle.de legacy".psk = "encrypted"; "platform/qca956x_wmac".ssids."jam-circle.de legacy".psk = "encrypted";
}; };
ap43.wifi."platform/qca955x_wmac".ssids."Kaffeetasse".psk = "encrypted";
ap44.wifi = { ap44.wifi = {
"1e140000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0".ssids."ZW stage legacy".psk = "encrypted"; "1e140000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0".ssids."ZW stage legacy".psk = "encrypted";
"1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0".ssids."ZW stage".psk = "encrypted"; "1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0".ssids."ZW stage".psk = "encrypted";
@ -226,7 +205,7 @@
"1e140000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0".ssids."ZW stage legacy".psk = "encrypted"; "1e140000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0".ssids."ZW stage legacy".psk = "encrypted";
"1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0".ssids."ZW stage".psk = "encrypted"; "1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0".ssids."ZW stage".psk = "encrypted";
}; };
ap5.wifi."platform/ahb/18100000.wmac".ssids."verbalwerk.de".psk = "encrypted"; ap5.wifi."platform/qca955x_wmac".ssids."verbalwerk.de".psk = "encrypted";
ap50.wifi = { ap50.wifi = {
"1e140000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0".ssids = { "1e140000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0".ssids = {
"ZW stage legacy".psk = "encrypted"; "ZW stage legacy".psk = "encrypted";
@ -236,7 +215,7 @@
}; };
ap51.wifi = { ap51.wifi = {
"pci0000:01/0000:01:00.0".ssids."antrares".psk = "encrypted"; "pci0000:01/0000:01:00.0".ssids."antrares".psk = "encrypted";
"platform/ahb/18100000.wmac".ssids."antrares".psk = "encrypted"; "platform/qca955x_wmac".ssids."antrares".psk = "encrypted";
}; };
ap52.wifi = { ap52.wifi = {
"1e140000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0".ssids."ZW stage legacy".psk = "encrypted"; "1e140000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0".ssids."ZW stage legacy".psk = "encrypted";
@ -245,82 +224,17 @@
ap53.wifi."platform/qca953x_wmac".ssids."Karen Koschnick".psk = "encrypted"; ap53.wifi."platform/qca953x_wmac".ssids."Karen Koschnick".psk = "encrypted";
ap54.wifi = { ap54.wifi = {
"pci0000:00/0000:00:00.0".ssids."Abyssinia".psk = "encrypted"; "pci0000:00/0000:00:00.0".ssids."Abyssinia".psk = "encrypted";
"platform/ahb/18100000.wmac".ssids."Abyssinia".psk = "encrypted"; "platform/qca956x_wmac".ssids."Abyssinia".psk = "encrypted";
}; };
ap55.wifi = { ap55.wifi = {
"pci0000:00/0000:00:00.0".ssids."MagLAN".psk = "encrypted"; "pci0000:00/0000:00:00.0".ssids."MagLAN".psk = "encrypted";
"platform/ahb/18100000.wmac".ssids."MagLAN (legacy)".psk = "encrypted"; "platform/qca956x_wmac".ssids."MagLAN (legacy)".psk = "encrypted";
}; };
ap56.wifi = { ap56.wifi = {
"pci0000:00/0000:00:00.0".ssids."MagLAN".psk = "encrypted"; "pci0000:00/0000:00:00.0".ssids."MagLAN".psk = "encrypted";
"platform/ahb/18100000.wmac".ssids."MagLAN (legacy)".psk = "encrypted"; "platform/qca956x_wmac".ssids."MagLAN (legacy)".psk = "encrypted";
};
ap57.wifi = {
"pci0000:00/0000:00:00.0".ssids."Zentralwerk".psk = "encrypted";
};
ap58.wifi = {
"pci0000:00/0000:00:00.0".ssids."Zentralwerk".psk = "encrypted";
"platform/ahb/18100000.wmac".ssids."LIZA".psk = "encrypted";
};
ap59.wifi = {
"pci0000:00/0000:00:00.0".ssids."Ebs 5000".psk = "encrypted";
"platform/ahb/18100000.wmac".ssids."Ebs 2000".psk = "encrypted";
};
ap60.wifi = {
"pci0000:00/0000:00:00.0".ssids."Abyssinia".psk = "encrypted";
"platform/ahb/18100000.wmac".ssids."Abyssinia".psk = "encrypted";
};
ap61.wifi = {
"pci0000:00/0000:00:00.0".ssids."tomiru".psk = "encrypted";
"platform/ahb/18100000.wmac".ssids."tomiru".psk = "encrypted";
};
ap62.wifi = {
"pci0000:00/0000:00:00.0".ssids."Wolke7".psk = "encrypted";
"platform/ahb/18100000.wmac".ssids."Wolke7 legacy".psk = "encrypted";
};
ap63.wifi = {
"pci0000:00/0000:00:00.0".ssids."EckiTino".psk = "encrypted";
"platform/ahb/18100000.wmac".ssids."EckiTino legacy".psk = "encrypted";
};
ap64.wifi = {
"platform/ahb/18100000.wmac".ssids."Princess Castle".psk = "encrypted";
};
ap65.wifi = {
"1e140000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0".ssids = {
"farbwerk".psk = "encrypted";
"Kaffeetasse".psk = "encrypted";
};
"1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0".ssids."farbwerk".psk = "encrypted";
};
ap66.wifi = {
"pci0000:00/0000:00:00.0".ssids."Buschfunk4.03".psk = "encrypted";
"platform/ahb/18100000.wmac".ssids."Buschfunk4.03 legacy".psk = "encrypted";
};
ap67.wifi = {
"1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0".ssids."farbwerk".psk = "encrypted";
"1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0+1".ssids."farbwerk".psk = "encrypted";
};
ap68.wifi = {
"1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0".ssids."farbwerk".psk = "encrypted";
"1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0+1".ssids."farbwerk".psk = "encrypted";
};
ap69.wifi = {
"pci0000:00/0000:00:00.0".ssids."LIZA".psk = "encrypted";
"platform/ahb/18100000.wmac".ssids."LIZA".psk = "encrypted";
}; };
ap7.wifi."platform/qca953x_wmac".ssids."mino".psk = "encrypted"; ap7.wifi."platform/qca953x_wmac".ssids."mino".psk = "encrypted";
ap70.wifi = {
"pci0000:00/0000:00:00.0".ssids."M".psk = "encrypted";
"platform/ahb/18100000.wmac".ssids."M legacy".psk = "encrypted";
};
ap72.wifi = {
"1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0".ssids."farbwerk".psk = "encrypted";
"1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0+1".ssids."farbwerk".psk = "encrypted";
};
ap73.wifi = {
"1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0".ssids."Princess Castle".psk = "encrypted";
"1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0+1".ssids."Princess Castle".psk = "encrypted";
};
ap8.wifi = { ap8.wifi = {
"pci0000:00/0000:00:00.0".ssids."C3D2".psk = "encrypted"; "pci0000:00/0000:00:00.0".ssids."C3D2".psk = "encrypted";
"platform/ar934x_wmac".ssids = { "platform/ar934x_wmac".ssids = {
@ -331,18 +245,5 @@
ap9.wifi."platform/qca953x_wmac".ssids."Herzzbuehne".psk = "encrypted"; ap9.wifi."platform/qca953x_wmac".ssids."Herzzbuehne".psk = "encrypted";
}; };
site.dyndnsKey = "oYmxXCIa0nArp0679L6v+y/UfnhripOudLv+R5Cop8I="; site.dyndnsKey = "SECRET";
site.vpn.wireguard = {
privateKey = "wPNXY4ED3Jz3Kz0KOmvfQOou6/wHrgqSsykaMYrtb28=";
peers = [ {
# privateKey: GOdfeizQZjPmyYnh3LMI3LrYeEtqYMyOvK8KASVgI1Q=
publicKey = "4aTjdm/APMTERczvtnLXRFYjSWYsmwPFTumjyno4nx4=";
allowedIPs = [
"172.20.76.226"
"fd23:42:c3d2:585::/64"
"2a00:8180:2c00:285::/64"
];
} ];
};
} }

View File

@ -14,7 +14,7 @@ let
) )
) {} (builtins.attrValues containers); ) {} (builtins.attrValues containers);
makeServer = _name: { makeServer = name: {
role = "server"; role = "server";
model = "pc"; model = "pc";
interfaces = bridgeInterfaces // { interfaces = bridgeInterfaces // {

View File

@ -7,58 +7,16 @@
interfaces = { mgmt.type = "phys"; }; interfaces = { mgmt.type = "phys"; };
links = { links = {
switch-a2.ports = [ "7" ]; switch-c1.ports = [ "7" ];
priv25.ports = [ priv25.ports = [ "2" "3" "4" "5" ];
# A6: Kleiner Saal Schaltschrank priv31.ports = [ "6" ];
"1" pub.ports = [ "8" ];
# Kabinett A10 iso4.ports = [ "1" ];
"2"
"3"
# A16: Buehne rechts unten
"4"
# artnet node
"5"
# Panel A2: Foyer
"8"
# Panel A8: Kleiner Saal Buehne
];
priv31.ports = [
# A4: Buero
"6"
];
# A3: Techniklager
# (DS23: Hackcenter vor kleinem Saal)
# A17: Grosser Saal ueber der Buehne
# switch-a2 Port 13
# Panel A6: kl Saal hinten
}; };
}; };
switch-a2 = { switch-b1 = {
role = "switch"; role = "switch";
model = "dumb"; model = "linksys-srw2048";
location = "Saal A";
links = {
switch-c1.ports = [ "1" ];
switch-a1.ports = [ "2" ];
switch-ds1.ports = [ "3" ];
switch-ds2.ports = [ "4" ];
switch-ds3.ports = [ "5" ];
ap44.ports = [ "10" ];
ap45.ports = [ "11" ];
ap46.ports = [ "12" ];
ap47.ports = [ "13" ];
ap48.ports = [ "14" ];
ap49.ports = [ "15" ];
ap50.ports = [ "16" ];
ap52.ports = [ "17" ];
};
};
switch-b3 = {
role = "switch";
model = "junos";
location = "Haus B Souterrain"; location = "Haus B Souterrain";
interfaces = { mgmt.type = "phys"; }; interfaces = { mgmt.type = "phys"; };
@ -68,144 +26,127 @@
# Ports 21-24 unten seitlich (optional optisch) # Ports 21-24 unten seitlich (optional optisch)
# Port 7 geht aktuell nach Turm C Erdgeschoss und dadurch zur Ecce # Port 7 geht aktuell nach Turm C Erdgeschoss und dadurch zur Ecce
links = { links = {
ap23.ports = [ "ge-0/0/10" ]; ap23.ports = [ "g10" ];
ap8.ports = [ "ge-0/0/16" ]; ap8.ports = [ "g16" ];
iso1.ports = [ "ge-0/0/2" ]; c3d2.ports = [ "g23" ];
iso2.ports = [ "ge-0/0/3" ]; iso1.ports = [ "g2" ];
iso3.ports = [ "ge-0/0/4" ]; iso2.ports = [ "g3" ];
coloradio.ports = [ iso3.ports = [ "g4" ];
# Patchpanel C8 mgmt.ports = [ "g1" ];
"ge-0/0/22" serv.ports = [ "g22" ];
]; # server1 had g46,g47,g48 too but this switch has too few
c3d2.ports = [ # port-channel groups
"ge-0/0/5" server1.ports = [ "g24" ];
"ge-0/0/8"
# riscbert
"ge-0/0/13"
];
server1 = {
group = "3";
ports = [
"ge-0/0/24"
"ge-0/0/25"
"ge-1/0/24"
"ge-1/0/25"
];
};
server2 = { server2 = {
group = "1"; group = "1";
ports = [ ports = [ "g12" "g38" "g39" "g40" ];
"ge-0/0/38" "ge-0/0/39"
"ge-1/0/32" "ge-1/0/33"
];
}; };
hydra = { server5 = {
group = "6";
ports = [ "g17" "g18" "g19" "g20" ];
};
server6 = {
group = "8";
ports = [ "g5" "g6" "g7" "g8" ];
};
server7 = {
group = "7"; group = "7";
trunk = false; ports = [ "g9" "g11" "g14" "g15" ];
ports = [
"ge-0/0/14" "ge-0/0/15"
"ge-1/0/14" "ge-1/0/15"
];
}; };
server10 = { server8 = {
group = "5"; group = "5";
ports = [ ports = [ "g35" "g36" "g37" "g13" ];
"ge-0/0/36" "ge-0/0/37" };
"ge-1/0/36" "ge-1/0/37" switch-b2 = {
]; group = "3";
ports = [ "g25" "g26" "g27" "g28" ];
}; };
switch-c1 = { switch-c1 = {
group = "2"; group = "2";
ports = [ "ge-0/0/30" "ge-0/0/31" "ge-1/0/30" "ge-1/0/31" ]; ports = [ "g29" "g30" "g31" "g32" ];
}; };
switch-c3d2-main = { switch-c3d2-main = {
group = "4"; group = "4";
ports = [ ports = [ "g41" "g42" "g43" "g44" ];
"ge-0/0/26"
"ge-0/0/27"
"ge-1/0/26"
"ge-1/0/27"
];
}; };
switch-d1.ports = [ "ge-0/0/34" ]; switch-d1.ports = [ "g34" ];
};
};
switch-b2 = {
role = "switch";
model = "3com-4200G";
location = "Haus B Souterrain";
interfaces = { mgmt.type = "phys"; };
ap1.ports = [ "ge-1/0/8" ]; links = {
ap11.ports = [ "ge-1/0/10" ]; ap1.ports = [ "GigabitEthernet 1/0/8" ];
ap34.ports = [ "ge-1/0/12" ]; ap11.ports = [ "GigabitEthernet 1/0/10" ];
ap18.ports = [ "ge-1/0/18" ]; ap15.ports = [ "GigabitEthernet 1/0/12" ];
ap29.ports = [ "ge-0/0/46" ]; ap18.ports = [ "GigabitEthernet 1/0/18" ];
ap30.ports = [ "ge-1/0/22" ]; ap24.ports = [ "GigabitEthernet 1/0/34" ];
ap35.ports = [ "ge-1/0/23" ]; ap25.ports = [ "GigabitEthernet 1/0/35" ];
ap37.ports = [ "ge-1/0/39" ]; ap29.ports = [ "GigabitEthernet 1/0/36" ];
ap63.ports = [ "ge-1/0/17" ]; ap30.ports = [ "GigabitEthernet 1/0/22" ];
ap40.ports = [ "ge-1/0/21" ]; ap35.ports = [ "GigabitEthernet 1/0/23" ];
ap41.ports = [ "ge-0/0/47" ]; ap37.ports = [ "GigabitEthernet 1/0/39" ];
ap42.ports = [ "ge-1/0/6" ]; ap39.ports = [ "GigabitEthernet 1/0/17" ];
ap5.ports = [ "ge-1/0/7" ]; ap40.ports = [ "GigabitEthernet 1/0/21" ];
ap51.ports = [ "ge-1/0/13" ]; ap41.ports = [ "GigabitEthernet 1/0/37" ];
ap53.ports = [ "ge-0/0/7" ]; ap42.ports = [ "GigabitEthernet 1/0/6" ];
ap72.ports = [ "ge-1/0/38" ]; ap5.ports = [ "GigabitEthernet 1/0/7" ];
ap55.ports = [ "ge-1/0/19" ]; ap51.ports = [ "GigabitEthernet 1/0/13" ];
ap56.ports = [ "ge-1/0/9" ]; ap53.ports = [ "GigabitEthernet 1/0/15" ];
ap60.ports = [ "ge-1/0/20" ]; ap54.ports = [ "GigabitEthernet 1/0/38" ];
ap62.ports = [ "ge-0/0/11" ]; ap55.ports = [ "GigabitEthernet 1/0/19" ];
ap65.ports = [ "ge-0/0/9" ]; ap56.ports = [ "GigabitEthernet 1/0/9" ];
ap66.ports = [ "ge-1/0/43" ];
mgmt.ports = [ mgmt.ports = [
"ge-0/0/0" "GigabitEthernet1/0/1"
"ge-0/0/1" # server3
"ge-1/0/44" "GigabitEthernet1/0/41"
# server1
"GigabitEthernet1/0/42"
"GigabitEthernet1/0/43"
# server5
"GigabitEthernet1/0/44"
# server6
"GigabitEthernet1/0/45"
# server7 # server7
"ge-1/0/45" "GigabitEthernet1/0/46"
"ge-1/0/46"
# server8 # server8
"ge-1/0/47" "GigabitEthernet1/0/47"
# server9 # server9
"ge-1/0/48" "GigabitEthernet1/0/48"
]; ];
flpk.ports = [ priv1.ports = [ "GigabitEthernet 1/0/3" ];
# server7 priv19.ports = [ "GigabitEthernet 1/0/40" ];
"ge-0/0/40" priv2.ports = [ "GigabitEthernet 1/0/4" ];
]; priv24.ports = [ "GigabitEthernet 1/0/14" "GigabitEthernet 1/0/16" ];
priv1.ports = [ "ge-1/0/3" ]; priv3.ports = [ "GigabitEthernet 1/0/5" ];
priv19.ports = [ "ge-1/0/40" ];
priv2.ports = [ "ge-1/0/4" ];
priv24.ports = [ "ge-0/0/6" "ge-1/0/16" ];
priv3.ports = [ "ge-1/0/5" ];
priv30.ports = [ "ge-0/0/12" ];
priv49.ports = [ "ge-1/0/1" ];
ap67.ports = [ "ge-1/0/34" ];
ap68.ports = [ "ge-1/0/35" ];
ap69.ports = [ "ge-0/0/35" ];
ap73.ports = [ "ge-0/0/45" ];
pub.ports = [ pub.ports = [
"ge-1/0/11" "GigabitEthernet 1/0/11"
"GigabitEthernet 1/0/20"
"GigabitEthernet 1/0/24"
]; ];
server3 = {
group = "1";
ports = [ "GigabitEthernet1/0/30" "GigabitEthernet1/0/31" ];
};
server9 = { server9 = {
group = "10"; group = "3";
ports = [ ports = [
"ge-0/0/28" "GigabitEthernet1/0/2"
"ge-0/0/29" "GigabitEthernet1/0/29"
"ge-1/0/28" "GigabitEthernet1/0/32"
"ge-1/0/29"
]; ];
}; };
server8 = { switch-b1 = {
group = "6"; group = "2";
ports = [ ports = [
"ge-0/0/41" "TenGigabitEthernet 1/1/1"
"ge-0/0/42" "GigabitEthernet 1/0/25"
"ge-1/0/41" "GigabitEthernet 1/0/26"
"ge-1/0/42" "GigabitEthernet 1/0/27"
]; "GigabitEthernet 1/0/28"
};
server6 = {
group = "9";
ports = [
"ge-0/0/18"
"ge-0/0/19"
"ge-1/0/0"
"ge-1/0/2"
]; ];
}; };
}; };
@ -219,11 +160,11 @@
links = { links = {
# Saal A: durch dummen PoE-Switch mit Aggregation an ap44-50,52 + switch-a1 # Saal A: durch dummen PoE-Switch mit Aggregation an ap44-50,52 + switch-a1
switch-a2 = { switch-a1 = {
group = "1"; group = "1";
ports = [ "15-16" ]; ports = [ "15-16" ];
}; };
switch-b3 = { switch-b1 = {
group = "2"; group = "2";
ports = [ "21-24" ]; ports = [ "21-24" ];
}; };
@ -238,15 +179,13 @@
ap19.ports = [ "17" ]; ap19.ports = [ "17" ];
ap26.ports = [ "18" ]; ap26.ports = [ "18" ];
ap38.ports = [ "7" ]; ap38.ports = [ "7" ];
ap61.ports = [ "13" ];
# Iso nets # Iso nets
iso1.ports = [ "9" ]; iso1.ports = [ "9" ];
iso2.ports = [ "10" ]; iso2.ports = [ "10" ];
iso3.ports = [ "11" ]; iso3.ports = [ "11" ];
iso4.ports = [ "12" ]; iso4.ports = [ "12" ];
iso5.ports = [ "13" ];
iso6.ports = [ "14" ]; iso6.ports = [ "14" ];
# Saal Foyer
priv25.ports = [ "20" ];
}; };
}; };
@ -258,7 +197,7 @@
links = { links = {
mgmt.ports = [ "1" ]; mgmt.ports = [ "1" ];
switch-b3 = { switch-b1 = {
group = "1"; group = "1";
ports = [ "21-24" ]; ports = [ "21-24" ];
}; };
@ -269,8 +208,11 @@
# Fenster # Fenster
ap33.ports = [ "5" ]; ap33.ports = [ "5" ];
c3d2.ports = [ "8-20" ]; c3d2.ports = [ "8-20" ];
# Testing
ap-test1.ports = [ "4" ];
bmx.ports = [ "7" ];
# tmp Datenspuren: VOC # tmp Datenspuren: VOC
iso4.ports = [ "4" "6" "7" ]; iso4.ports = [ "6" ];
}; };
}; };
@ -281,13 +223,12 @@
interfaces = { mgmt.type = "phys"; }; interfaces = { mgmt.type = "phys"; };
links = { links = {
switch-b3 = { switch-b1 = {
group = "1"; group = "1";
ports = [ "1" ]; ports = [ "1" ];
}; };
switch-d2.ports = [ "3" ];
# Turm D APs # Turm D APs
ap3.ports = [ "3" ];
ap7.ports = [ "8" ]; ap7.ports = [ "8" ];
ap9.ports = [ "5" ]; ap9.ports = [ "5" ];
ap10.ports = [ "4" ]; ap10.ports = [ "4" ];
@ -296,21 +237,6 @@
}; };
}; };
switch-d2 = {
role = "switch";
model = "dumb";
location = "Turm D Durchgang 1. Etage";
links = {
switch-d1 = {
group = "1";
ports = [ "12" ];
};
ap3.ports = [ "1" ];
ap59.ports = [ "2" ];
};
};
switch-dach = { switch-dach = {
role = "switch"; role = "switch";
model = "HP-procurve-2824"; model = "HP-procurve-2824";
@ -321,149 +247,13 @@
mgmt.ports = [ "1" ]; mgmt.ports = [ "1" ];
switch-c1.ports = [ "24" ]; switch-c1.ports = [ "24" ];
# Freifunk nodes # Freifunk nodes
bmx.ports = [ "12,14,16" ]; bmx.ports = [ "10-19" ];
# radiobert # radiobert
serv.ports = [ "7" ]; serv.ports = [ "6-9" ];
# Starlink # Starlink
up3.ports = [ "3" ]; up3.ports = [ "3" ];
# unifiac-mesh
ap57.ports = [ "10" ];
# TLMS tetra and traffic-stop-box
c3d2.ports = [ "19,20" ];
};
};
switch-ds1 = {
role = "switch";
model = "3com-5500G";
location = "Foyer";
interfaces = { mgmt.type = "phys"; };
links = {
# Public
pub.ports = [
"GigabitEthernet1/0/1"
"GigabitEthernet1/0/2"
"GigabitEthernet1/0/3"
"GigabitEthernet1/0/4"
"GigabitEthernet1/0/5"
"GigabitEthernet1/0/6"
"GigabitEthernet1/0/7"
"GigabitEthernet1/0/8"
"GigabitEthernet1/0/9"
"GigabitEthernet1/0/10"
"GigabitEthernet1/0/11"
"GigabitEthernet1/0/12"
"GigabitEthernet1/0/13"
"GigabitEthernet1/0/14"
"GigabitEthernet1/0/15"
];
# Stage uplink
priv25.ports = [
"GigabitEthernet1/0/16"
"GigabitEthernet1/0/17"
"GigabitEthernet1/0/18"
"GigabitEthernet1/0/19"
];
# Freifunk
bmx.ports = [
"GigabitEthernet1/0/20"
"GigabitEthernet1/0/21"
"GigabitEthernet1/0/22"
"GigabitEthernet1/0/23"
];
# Uplink
switch-a2.ports = [ "GigabitEthernet1/0/24" ];
};
};
switch-ds2 = {
role = "switch";
model = "3com-5500G";
location = "Grosser Saal oben";
interfaces = { mgmt.type = "phys"; };
links = {
# Public
pub.ports = [
"GigabitEthernet1/0/1"
"GigabitEthernet1/0/2"
"GigabitEthernet1/0/3"
"GigabitEthernet1/0/4"
"GigabitEthernet1/0/5"
"GigabitEthernet1/0/6"
"GigabitEthernet1/0/7"
"GigabitEthernet1/0/8"
"GigabitEthernet1/0/9"
"GigabitEthernet1/0/10"
"GigabitEthernet1/0/11"
"GigabitEthernet1/0/12"
"GigabitEthernet1/0/13"
"GigabitEthernet1/0/14"
"GigabitEthernet1/0/15"
"GigabitEthernet1/0/16"
"GigabitEthernet1/0/17"
"GigabitEthernet1/0/18"
"GigabitEthernet1/0/19"
];
# Stage uplink
priv25.ports = [
"GigabitEthernet1/0/20"
"GigabitEthernet1/0/21"
];
# VOC isolated
iso4.ports = [
"GigabitEthernet1/0/22"
"GigabitEthernet1/0/23"
];
# Uplink
switch-a2.ports = [ "GigabitEthernet1/0/24" ];
};
};
switch-ds3 = {
firstboot = true;
role = "switch";
model = "3com-5500G";
location = "Kleiner Saal";
interfaces = { mgmt.type = "phys"; };
links = {
# Public
pub.ports = [
"GigabitEthernet1/0/1"
"GigabitEthernet1/0/2"
"GigabitEthernet1/0/3"
"GigabitEthernet1/0/4"
"GigabitEthernet1/0/5"
"GigabitEthernet1/0/6"
"GigabitEthernet1/0/7"
"GigabitEthernet1/0/8"
"GigabitEthernet1/0/9"
"GigabitEthernet1/0/10"
"GigabitEthernet1/0/11"
"GigabitEthernet1/0/12"
"GigabitEthernet1/0/13"
"GigabitEthernet1/0/14"
"GigabitEthernet1/0/15"
"GigabitEthernet1/0/16"
"GigabitEthernet1/0/17"
"GigabitEthernet1/0/18"
"GigabitEthernet1/0/19"
];
# Stage uplink
priv25.ports = [
"GigabitEthernet1/0/20"
"GigabitEthernet1/0/21"
];
# VOC isolated
iso4.ports = [
"GigabitEthernet1/0/22"
"GigabitEthernet1/0/23"
];
# Uplink
switch-a2.ports = [ "GigabitEthernet1/0/24" ];
}; };
}; };
}; };
} }

View File

@ -18,15 +18,11 @@ in
c3d2 = 5; c3d2 = 5;
cluster = 6; cluster = 6;
bmx = 7; bmx = 7;
flpk = 8;
coloradio = 9;
# Modems # Modems
up1 = 10; up1 = 10;
up2 = 11; up2 = 11;
up3 = 12; up3 = 12;
up4 = 13; up4 = 13;
# Isolated other stuff
c3d2iot = 20;
# Isolated neighbors directly connectied with their modems # Isolated neighbors directly connectied with their modems
iso1 = 101; iso1 = 101;
iso2 = 102; iso2 = 102;

Binary file not shown.

View File

@ -55,14 +55,10 @@ Von geeigneten Routern haben wir stets zu wenige übrig, so dass wir sie
gemeinsam kaufen und bezahlen müssen. Such dir einen aus, dann gemeinsam kaufen und bezahlen müssen. Such dir einen aus, dann
bestellen und konfigurieren wir ihn. bestellen und konfigurieren wir ihn.
* Zyxel WSM20 (Multy M1) ([25€](https://geizhals.de/zyxel-multy-m1-v101058.html))
* TP-Link Archer C7 v2 ([58€](http://geizhals.de/tp-link-archer-c7-v2-a923544.html)) * TP-Link Archer C7 v2 ([58€](http://geizhals.de/tp-link-archer-c7-v2-a923544.html))
* Ubiquiti UniFi nanoHD ([150€](https://geizhals.de/ubiquiti-unifi-nanohd-uap-nanohd-a1802819.html))
* [Jedes Gerät auf dem OpenWRT läuft](https://openwrt.org/supported_devices) * [Jedes Gerät auf dem OpenWRT läuft](https://openwrt.org/supported_devices)
Die genannten Preise sind unverbindlich und schwanken stark mit den
Situationen rund um die Straße von Malaka, Rotem Meer und
Suez-Kanal. Auf eBay gibts gebrauchte Geräte.
![WLAN-Router](https://upload.wikimedia.org/wikipedia/commons/thumb/3/34/Linksys-Wireless-G-Router.jpg/280px-Linksys-Wireless-G-Router.jpg) ![WLAN-Router](https://upload.wikimedia.org/wikipedia/commons/thumb/3/34/Linksys-Wireless-G-Router.jpg/280px-Linksys-Wireless-G-Router.jpg)
### Netzverteilung ### Netzverteilung
@ -158,8 +154,11 @@ mitbenutzen indem wir dir ein [VLAN](https://de.wikipedia.org/wiki/VLAN)
konfigurieren, welches nur dein Kabelmodem und deine Datendose bekommen. konfigurieren, welches nur dein Kabelmodem und deine Datendose bekommen.
--- # Sprechstunden
Dienstags und Donnerstags 16:00-18:00 Uhr
[C3D2](https://www.c3d2.de/space.html), Haus B Souterrain, genau in der Mitte [C3D2](https://www.c3d2.de/space.html), Haus B Souterrain, genau in der Mitte
![Kernnetz visualisiert von eri!](core.png) ![Kernnetz visualisiert von eri!](core.png)

View File

@ -1,16 +0,0 @@
# Wireguard VPN Dialin
## wg-quick template
```ini
[Interface]
Address = 172.20.76.TODO/28
Address = fd23:42:c3d2:585::TODO/64
Address = 2a00:8180:2c00:285::TODO/64
PrivateKey = TODO
[Peer]
PublicKey = PG2VD0EB+Oi+U5/uVMUdO5MFzn59fAck6hz8GUyLMRo=
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = upstream4.dyn.zentralwerk.org:1337
```

View File

@ -1,53 +1,32 @@
{ {
"nodes": { "nodes": {
"dns-nix": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1703643450,
"narHash": "sha256-EUUF5oxFFPX/etKm0FNQg+7MPHQlNjmM1XhNgyDf7A0=",
"owner": "SuperSandro2000",
"repo": "dns.nix",
"rev": "70dcce71560d4253f63812fa36dee994c81ae814",
"type": "github"
},
"original": {
"owner": "SuperSandro2000",
"repo": "dns.nix",
"type": "github"
}
},
"flake-utils": {
"locked": {
"lastModified": 1614513358,
"narHash": "sha256-LakhOx3S1dRjnh0b5Dg3mbZyH0ToC9I8Y2wKSkBaTzU=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "5466c5bbece17adaab2d82fae80b46e807611bf3",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1717104653, "lastModified": 1641924320,
"narHash": "sha256-0ZkToL+IOOP3xw0JPgTj8WP8aeKwxNNiG3gr6prfnig=", "narHash": "sha256-DuOpJqoMmQ3Yk4C64QQHFaByhbSIi872He6z5BXY1YM=",
"owner": "SuperSandro2000", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "b15c037e83ebf28278abc1769df8792ea30a223f", "rev": "05f3de54d568dba52efaad966f0e09bfea796dcb",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "SuperSandro2000", "owner": "NixOS",
"ref": "nixos-24.05", "ref": "release-21.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-master": {
"locked": {
"lastModified": 1641927215,
"narHash": "sha256-96otEPy5y/4aeM6Sjl//Qr8v3+CdjTBNtnS4eKyoY0U=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "0fdbcb2355f0681908cc9fef0cc9138f938ae1a3",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
@ -55,46 +34,25 @@
"openwrt": { "openwrt": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1713442482, "lastModified": 1641673875,
"narHash": "sha256-OAcv1qiM2V6wPQm4Tz2QnnDpw34pifG6QRDZea7AP9o=", "narHash": "sha256-Eb9tVxE9Pmob/xWZ6wRt95cTycPeyPkyyaaWaz6cWtA=",
"ref": "openwrt-23.05", "ref": "openwrt-21.02",
"rev": "9b33b74ef71225442361d5192d3a727be212c3cd", "rev": "6ced8cad8edd2a04fc6bb914c333c8aac9a1c825",
"revCount": 58296, "revCount": 50927,
"type": "git", "type": "git",
"url": "https://git.openwrt.org/openwrt/openwrt.git" "url": "https://git.openwrt.org/openwrt/openwrt.git"
}, },
"original": { "original": {
"ref": "openwrt-23.05", "ref": "openwrt-21.02",
"type": "git", "type": "git",
"url": "https://git.openwrt.org/openwrt/openwrt.git" "url": "https://git.openwrt.org/openwrt/openwrt.git"
} }
}, },
"openwrt-imagebuilder": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1713693953,
"narHash": "sha256-DsJ/pzBSF3CxQWyiw4V3k96h7Q3UaRnQnL1N9tw+uWg=",
"owner": "astro",
"repo": "nix-openwrt-imagebuilder",
"rev": "d4dc8c84f4397be494ae834709276f099df892e7",
"type": "github"
},
"original": {
"owner": "astro",
"repo": "nix-openwrt-imagebuilder",
"type": "github"
}
},
"root": { "root": {
"inputs": { "inputs": {
"dns-nix": "dns-nix",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"openwrt": "openwrt", "nixpkgs-master": "nixpkgs-master",
"openwrt-imagebuilder": "openwrt-imagebuilder" "openwrt": "openwrt"
} }
} }
}, },

View File

@ -2,22 +2,13 @@
description = "Zentralwerk network"; description = "Zentralwerk network";
inputs = { inputs = {
dns-nix = { nixpkgs.url = "github:NixOS/nixpkgs/release-21.11";
url = "github:SuperSandro2000/dns.nix"; nixpkgs-master.url = "github:NixOS/nixpkgs";
inputs.nixpkgs.follows = "nixpkgs"; openwrt.url = "git+https://git.openwrt.org/openwrt/openwrt.git?ref=openwrt-21.02";
}; openwrt.flake = false;
nixpkgs.url = "github:SuperSandro2000/nixpkgs/nixos-24.05";
openwrt = {
url = "git+https://git.openwrt.org/openwrt/openwrt.git?ref=openwrt-23.05";
flake = false;
};
openwrt-imagebuilder = {
url = "github:astro/nix-openwrt-imagebuilder";
inputs.nixpkgs.follows = "nixpkgs";
};
}; };
outputs = inputs@{ self, dns-nix, nixpkgs, openwrt, openwrt-imagebuilder }: outputs = inputs@{ self, nixpkgs, nixpkgs-master, openwrt }:
let let
system = "x86_64-linux"; system = "x86_64-linux";
systems = [ system ]; systems = [ system ];
@ -27,23 +18,24 @@
self.lib.nixosSystem { self.lib.nixosSystem {
inherit system; inherit system;
modules = [ self.nixosModule ]; modules = [ self.nixosModule ];
specialArgs = { specialArgs.hostName = name;
hostName = name; specialArgs.lib = self.lib;
inherit (self) lib; specialArgs.self = self;
inherit inputs dns-nix self; specialArgs.inputs = inputs;
}; specialArgs.nixpkgs-master = nixpkgs-master;
}; };
in { in {
# Config, and utilities # Config, and utilities
lib = nixpkgs.lib.extend (_final: _prev: lib = nixpkgs.lib.extend (final: prev:
import ./nix/lib { import ./nix/lib {
inherit self openwrt; inherit self;
inherit (nixpkgs.legacyPackages.x86_64-linux) lib pkgs; inherit openwrt;
pkgs = nixpkgs.legacyPackages.x86_64-linux;
}); });
# Everything that can be built locally outside of NixOS # Everything that can be built locally outside of NixOS
packages = forAllSystems (system: packages = forAllSystems (system:
import ./nix/pkgs { inherit self nixpkgs system openwrt-imagebuilder; } import ./nix/pkgs { inherit self nixpkgs system; }
); );
# Configuration for nixosConfigurations # Configuration for nixosConfigurations
@ -76,10 +68,12 @@
'' ''
); );
wrappers = { wrappers = {
"all-device-scripts" = hydraJob; "all-device-scripts" = pkg:
hydraJob pkg;
"export-config" = exportFileWrapper; "export-config" = exportFileWrapper;
"switch-.*" = exportFileWrapper; "switch-.*" = exportFileWrapper;
"ap.*-image" = exportFileWrapper; "ap.*" = exportFileWrapper;
}; };
in in
builtins.mapAttrs (name: pkg: builtins.mapAttrs (name: pkg:

View File

@ -4,14 +4,14 @@
let let
result = pkgs.lib.evalModules { result = pkgs.lib.evalModules {
args = {
inherit self pkgs;
};
modules = [ modules = [
( (
{ lib, ... }: { lib, ... }:
with lib; with lib;
{ {
config._module.args = {
inherit self pkgs;
};
options.assertions = mkOption { options.assertions = mkOption {
type = with types; listOf unspecified; type = with types; listOf unspecified;
internal = true; internal = true;

View File

@ -55,13 +55,13 @@ let
links' = builtins.tail links; links' = builtins.tail links;
in in
if config.site.hosts ? ${link} if config.site.hosts ? ${link}
then networksBehindLink' seen' (builtins.filter (link: ! seen' ? ${link}) ( then networksBehindLink' seen' (
links' ++ ( links' ++ (
builtins.attrNames config.site.hosts.${link}.interfaces builtins.attrNames config.site.hosts.${link}.interfaces
) ++ ( ) ++ (
onlyUnseen (builtins.attrNames config.site.hosts.${link}.links) onlyUnseen (builtins.attrNames config.site.hosts.${link}.links)
) )
)) )
else if config.site.net ? ${link} else if config.site.net ? ${link}
then networksBehindLink' seen' links' then networksBehindLink' seen' links'
@ -102,7 +102,7 @@ let
options = { options = {
vlan = mkOption { vlan = mkOption {
description = "VLAN tag number"; description = "VLAN tag number";
type = with types; nullOr int; type = types.int;
}; };
subnet4 = mkOption { subnet4 = mkOption {
description = "v.w.x.y/z"; description = "v.w.x.y/z";
@ -158,11 +158,6 @@ let
type = with types; nullOr (submodule { options = dhcpOpts; }); type = with types; nullOr (submodule { options = dhcpOpts; });
default = null; default = null;
}; };
ipv6Router = mkOption {
description = "Who sends router advertisements?";
type = with types; nullOr str;
default = config.site.net.${name}.dhcp.router or null;
};
domainName = mkOption { domainName = mkOption {
description = "Domain name option"; description = "Domain name option";
type = types.str; type = types.str;
@ -178,7 +173,7 @@ let
type = enum [ "A" "AAAA" "MX" "SRV" "CNAME" "TXT" ]; type = enum [ "A" "AAAA" "MX" "SRV" "CNAME" "TXT" ];
}; };
data = mkOption { data = mkOption {
type = oneOf [ str (attrsOf (oneOf [ int str ])) ]; type = str;
}; };
}; };
}); });
@ -190,26 +185,6 @@ let
default = false; default = false;
description = "Domain updated by DHCP server?"; description = "Domain updated by DHCP server?";
}; };
mtu = mkOption {
type = with types; nullOr int;
default = null;
};
wifi.ieee80211rKey = mkOption {
type = with types; nullOr str;
default = null;
description = ''
Key between WiFi access points for Fast Transition
'';
};
captiveJson = mkOption {
type = with types; nullOr str;
default = null;
description = ''
Optional URL to Captive Portal JSON file.
See: <https://datatracker.ietf.org/doc/html/draft-ietf-capport-api>
'';
};
}; };
}; };
@ -230,11 +205,6 @@ let
type = with types; nullOr int; type = with types; nullOr int;
default = null; default = null;
}; };
noNat.subnets4 = mkOption {
type = with types; listOf str;
default = [];
description = "Do not NAT traffic from these public static subnets";
};
noNat.subnets6 = mkOption { noNat.subnets6 = mkOption {
type = with types; listOf str; type = with types; listOf str;
default = []; default = [];
@ -250,7 +220,7 @@ let
}; };
}; };
interfaceOpts = { ... }: { interfaceOpts = { name, ... }: {
options = { options = {
hwaddr = mkOption { hwaddr = mkOption {
type = with types; nullOr str; type = with types; nullOr str;
@ -258,7 +228,7 @@ let
description = "Static MAC address"; description = "Static MAC address";
}; };
type = mkOption { type = mkOption {
type = types.enum [ "phys" "veth" "pppoe" "bridge" "wireguard" "vxlan" ]; type = types.enum [ "phys" "veth" "pppoe" "bridge" "wireguard" ];
description = '' description = ''
veth: Virtual ethernet to be attached to a bridge. veth: Virtual ethernet to be attached to a bridge.
@ -301,16 +271,6 @@ let
}; };
}); });
}; };
vxlan = mkOption {
default = null;
type = with types; nullOr (submodule {
options = {
peer = mkOption {
type = str;
};
};
});
};
}; };
}; };
@ -369,8 +329,7 @@ let
# isRouter = Part of the core network? # isRouter = Part of the core network?
default = default =
config.site.hosts.${name}.interfaces ? core && config.site.hosts.${name}.interfaces ? core &&
config.site.net.core.hosts4 ? ${name} && config.site.net.core.hosts4 ? ${name};
config.site.hosts.${name}.role == "container";
description = "Should this host route?"; description = "Should this host route?";
}; };
firewall.enable = mkOption { firewall.enable = mkOption {
@ -421,11 +380,6 @@ let
default = []; default = [];
description = "Accept default routes from these OSPF routers, in order of preference"; description = "Accept default routes from these OSPF routers, in order of preference";
}; };
ospf.allowedUpstreams6 = mkOption {
type = with types; listOf str;
default = config.site.hosts.${name}.ospf.allowedUpstreams;
description = "Accept IPv6 default routes from these OSPF3 routers, in order of preference";
};
ospf.upstreamInstance = mkOption { ospf.upstreamInstance = mkOption {
type = with types; nullOr int; type = with types; nullOr int;
default = null; default = null;
@ -447,6 +401,16 @@ let
type = types.bool; type = types.bool;
default = false; default = false;
}; };
services.yggdrasil = {
enable = mkOption {
type = types.bool;
default = false;
};
keys = mkOption {
type = types.str;
default = "";
};
};
links = mkOption { links = mkOption {
description = "Which port is connected to what other device? Keys are either network names or known hostnames."; description = "Which port is connected to what other device? Keys are either network names or known hostnames.";
default = {}; default = {};
@ -455,25 +419,17 @@ let
wifi = mkOption { wifi = mkOption {
default = {}; default = {};
type = with types; attrsOf (submodule ( type = with types; attrsOf (submodule (
{ config, ... }: { { name, ... }: {
options = { options = {
band = mkOption {
type = enum [ "2g" "5g" ];
default =
if config.channel >= 1 && config.channel <= 14
then "2g"
else if config.channel >= 32 && config.channel <= 177
then "5g"
else throw "What band is channel ${toString config.channel}?";
};
htmode = mkOption { htmode = mkOption {
type = enum [ "HT20" "HT40-" "HT40+" "HT40" "VHT80" ]; type = enum [ "HT20" "HT40-" "HT40+" "VHT80" ];
}; };
channel = mkOption { channel = mkOption {
type = int; type = int;
}; };
ssids = mkOption { ssids = mkOption {
type = attrsOf (submodule ({ config, ... }: { type = attrsOf (submodule (
{ name, ... }: {
options = { options = {
net = mkOption { net = mkOption {
type = str; type = str;
@ -482,45 +438,13 @@ let
type = nullOr str; type = nullOr str;
default = null; default = null;
}; };
hidden = mkOption {
type = bool;
default = false;
};
encryption = mkOption {
type = enum [ "none" "owe" "wpa2" "wpa3" ];
default =
if config.psk == null
then "none"
else "wpa3";
};
mode = mkOption {
type = enum [ "ap" "sta" ];
default = "ap";
};
ifname = mkOption {
type = nullOr str;
default = null;
};
disassocLowAck = mkOption {
type = bool;
default = true;
description = ''
Disable for wireless bridges.
'';
};
};
}));
};
}; };
} }
)); ));
}; };
wifiOnLink.enable = mkOption { };
type = types.bool; }
default = true; ));
description = ''
Install the wifi-on-link.sh script on OpenWRT devices.
'';
}; };
}; };
}; };
@ -530,7 +454,7 @@ let
type = types.int; type = types.int;
}; };
peers = mkOption { peers = mkOption {
type = with types; attrsOf (submodule ({ ... }: { type = with types; attrsOf (submodule ({ name, ... }: {
options = { options = {
asn = mkOption { asn = mkOption {
type = types.int; type = types.int;
@ -560,12 +484,8 @@ let
vlans = mkOption { vlans = mkOption {
type = with types; listOf int; type = with types; listOf int;
description = "Automatically generated, do not set"; description = "Automatically generated, do not set";
default = builtins.concatMap (net: default = map (net:
let config.site.net.${net}.vlan
inherit (config.site.net.${net}) vlan;
in if vlan != null
then [ vlan ]
else []
) config.site.hosts.${hostName}.links.${name}.nets; ) config.site.hosts.${hostName}.links.${name}.nets;
}; };
trunk = mkOption { trunk = mkOption {
@ -580,30 +500,6 @@ let
}; };
}; };
}; };
vpnOpts = {
privateKey = mkOption {
type = types.str;
};
port = mkOption {
type = types.int;
default = 1337;
};
peers = mkOption {
type = with types; listOf (submodule {
options = {
publicKey = mkOption {
type = str;
};
allowedIPs = mkOption {
type = listOf str;
};
};
});
};
};
in in
{ {
options.site = { options.site = {
@ -613,7 +509,6 @@ in
type = with types; attrsOf (submodule netOpts); type = with types; attrsOf (submodule netOpts);
}; };
hosts = mkOption { hosts = mkOption {
description = "All the static hosts"; description = "All the static hosts";
default = {}; default = {};
@ -627,23 +522,6 @@ in
dyndnsKey = mkOption { dyndnsKey = mkOption {
type = types.str; type = types.str;
}; };
vpn.wireguard = vpnOpts;
mqttServer = {
host = mkOption {
type = types.str;
default = config.site.net.serv.hosts4.broker;
};
user = mkOption {
type = types.str;
default = "user";
};
password = mkOption {
type = types.str;
default = "secret";
};
};
}; };
config.warnings = config.warnings =
@ -678,7 +556,7 @@ in
else [] else []
) (builtins.attrNames config.site.hosts); ) (builtins.attrNames config.site.hosts);
in in
(reportCollisions "VLAN tag" (x: lib.optional (x.vlan != null) x.vlan) config.site.net) ++ (reportCollisions "VLAN tag" (x: [x.vlan]) config.site.net) ++
(reportCollisions "IPv4 subnet" (x: if x.subnet4 == null then [] else [x.subnet4]) config.site.net) ++ (reportCollisions "IPv4 subnet" (x: if x.subnet4 == null then [] else [x.subnet4]) config.site.net) ++
(reportCollisions "IPv6 subnet" (x: builtins.attrValues x.subnets6) config.site.net) ++ (reportCollisions "IPv6 subnet" (x: builtins.attrValues x.subnets6) config.site.net) ++
ospfUpstreamXorGw; ospfUpstreamXorGw;
@ -736,7 +614,7 @@ in
let let
vlan = toString config.site.net.${net}.vlan; vlan = toString config.site.net.${net}.vlan;
in in
if config.site.net.${net}.vlan != null && result ? ${vlan} if result ? ${vlan}
then result // { then result // {
"${vlan}" = result.${vlan} ++ [ net ]; "${vlan}" = result.${vlan} ++ [ net ];
} }
@ -747,67 +625,5 @@ in
in map (vlan: { in map (vlan: {
assertion = builtins.length vlanNets.${vlan} == 1; assertion = builtins.length vlanNets.${vlan} == 1;
message = "VLAN ${vlan} is used by more than one network: ${lib.concatStringsSep " " vlanNets.${vlan}}"; message = "VLAN ${vlan} is used by more than one network: ${lib.concatStringsSep " " vlanNets.${vlan}}";
}) (builtins.attrNames vlanNets)) }) (builtins.attrNames vlanNets));
++
# Duplicate switch port check
builtins.concatMap (hostName:
let
ports = lib.unique (
builtins.concatMap (linkName:
config.site.hosts.${hostName}.links.${linkName}.ports
) (builtins.attrNames config.site.hosts.${hostName}.links)
);
linksOfPort = port:
builtins.attrNames (
lib.filterAttrs (_: { ports, ... }: builtins.elem port ports)
config.site.hosts.${hostName}.links
);
in map (port: {
assertion = builtins.length (linksOfPort port) == 1;
message = "${hostName}: port ${port} is used in more than one link: ${lib.concatStringsSep " " (linksOfPort port)}";
}) ports
) (builtins.attrNames config.site.hosts)
++
# Duplicate switch port group check
builtins.concatMap (hostName:
let
groups = lib.unique (
builtins.filter builtins.isString (
builtins.map (linkName:
config.site.hosts.${hostName}.links.${linkName}.group
) (builtins.attrNames config.site.hosts.${hostName}.links)
)
);
linksOfGroup = wantedGroup:
builtins.attrNames (
lib.filterAttrs (_: { group, ... }: group == wantedGroup)
config.site.hosts.${hostName}.links
);
in map (group: {
assertion = builtins.length (linksOfGroup group) == 1;
message = "${hostName}: group ${group} is used in more than one link: ${lib.concatStringsSep " " (linksOfGroup group)}";
}) groups
) (builtins.attrNames config.site.hosts)
++
# wifi psk checks
builtins.concatMap (hostName:
builtins.concatMap (wifiPath:
map (ssid:
let
ssidConf = config.site.hosts.${hostName}.wifi.${wifiPath}.ssids.${ssid};
in
if builtins.elem ssidConf.encryption [ "none" "owe" ]
then {
assertion = ssidConf.psk == null;
message = "${hostName}: SSID ${ssid} has encryption ${ssidConf.encryption} but a PSK is set";
}
else if builtins.elem ssidConf.encryption [ "wpa2" "wpa3" ]
then {
assertion = ssidConf.psk != null;
message = "${hostName}: SSID ${ssid} has encryption ${ssidConf.encryption} but no PSK is set";
}
else throw "Unsupported WiFi encryption ${ssidConf.encryption}"
) (builtins.attrNames config.site.hosts.${hostName}.wifi.${wifiPath}.ssids)
) (builtins.attrNames config.site.hosts.${hostName}.wifi)
) (builtins.attrNames config.site.hosts);
} }

View File

@ -1,13 +1,13 @@
{ self, lib, openwrt, pkgs }: { self, pkgs, openwrt }:
rec { rec {
inherit (import ./config { inherit self pkgs; }) config; config = (import ./config { inherit self pkgs; }).config;
netmasks = import ./netmasks.nix; netmasks = import ./netmasks.nix;
subnet = import ./subnet { inherit pkgs; }; subnet = import ./subnet { inherit pkgs; };
dns = import ./dns.nix { inherit config lib; }; dns = import ./dns.nix { inherit pkgs config; };
openwrtModels = import ./openwrt-models.nix { inherit self openwrt; }; openwrtModels = import ./openwrt-models.nix { inherit self openwrt; };
@ -15,9 +15,8 @@ rec {
let let
models = models =
builtins.filter ({ models, ... }: builtins.filter ({ models, ... }:
self.lib.any ({ model, vendor, ... }: self.lib.any ({ model, ... }:
model == wantedModel || model == wantedModel
"${vendor}_${model}" == wantedModel
) models ) models
) openwrtModels; ) openwrtModels;
result = result =

View File

@ -1,18 +1,15 @@
{ config, lib }: { pkgs, config }:
let
lib = pkgs.lib;
in
rec { rec {
ns = "dns.serv.zentralwerk.org"; ns = "dns.serv.zentralwerk.org";
internalNS = [ ns ]; internalNS = [ ns ];
# public servers (slaves) # public servers (slaves)
publicNS = [ publicNS = [ "ns.c3d2.de" "ns.spaceboyz.net" ];
"ns.c3d2.de"
"ns.spaceboyz.net"
"ns1.supersandro.de"
];
publicIPv4 = config.site.hosts.upstream4.interfaces.up4-pppoe.upstream.staticIpv4Address; dynamicReverseZones = [
dynamicReverseZones4 = [
"73.20.172.in-addr.arpa" "73.20.172.in-addr.arpa"
"74.20.172.in-addr.arpa" "74.20.172.in-addr.arpa"
"75.20.172.in-addr.arpa" "75.20.172.in-addr.arpa"
@ -21,25 +18,7 @@ rec {
"78.20.172.in-addr.arpa" "78.20.172.in-addr.arpa"
"79.20.172.in-addr.arpa" "79.20.172.in-addr.arpa"
"99.22.172.in-addr.arpa" "99.22.172.in-addr.arpa"
"22.10.in-addr.arpa"
]; ];
dynamicReverseZones6 = [
"2.0.0.0.c.2.0.8.1.8.0.0.a.2.ip6.arpa"
"4.1.b.a.c.a.2.8.3.5.f.0.a.2.ip6.arpa"
"5.0.2.d.3.c.2.4.0.0.3.2.d.f.ip6.arpa"
];
mapI = start: end: f:
if start >= end
then []
else [ (f start) ] ++ mapI (start + 1) end f;
isRfc1918Reverse = reverse:
builtins.any (suffix: lib.hasSuffix suffix reverse) ([
"10.in-addr.arpa"
"168.192.in-addr.arpa"
] ++ mapI 0 32 (i:
"${toString (16 + i)}.172.in-addr.arpa"
));
localZones = localZones =
let let
@ -64,9 +43,8 @@ rec {
); );
# generate zones only for nets with hosts # generate zones only for nets with hosts
namedNets = lib.filterAttrs (_name: { hosts4, hosts6, dynamicDomain, ... }: namedNets = lib.filterAttrs (name: { hosts4, hosts6, dynamicDomain, ... }:
hosts4 != {} || (hosts4 != [] && hosts6 != []) ||
hosts6 != {} ||
dynamicDomain dynamicDomain
) config.site.net; ) config.site.net;
@ -99,7 +77,7 @@ rec {
"${zone}" = true; "${zone}" = true;
} }
) {} (builtins.attrNames reverseHosts4) ) {} (builtins.attrNames reverseHosts4)
) ++ dynamicReverseZones4 ) ++ dynamicReverseZones
); );
# turns `::` into `0000:0000:0000:0000:0000:0000:0000:0000` # turns `::` into `0000:0000:0000:0000:0000:0000:0000:0000`
@ -149,8 +127,10 @@ rec {
let let
domain = domain =
if ctx == "dn42" if ctx == "dn42"
then "${net}.zentralwerk.dn42" then namedNets.${net}.domainName
else namedNets.${net}.domainName; else if builtins.match "up.*" ctx != null
then "${net}.zentralwerk.org"
else throw "Invalid IPv6 context: ${ctx}";
in in
lib.recursiveUpdate result { lib.recursiveUpdate result {
"${ipv6ToReverse hosts.${host}}" = "${host}.${domain}"; "${ipv6ToReverse hosts.${host}}" = "${host}.${domain}";
@ -160,10 +140,9 @@ rec {
)) {} (builtins.attrNames namedNets); )) {} (builtins.attrNames namedNets);
# `{ dn42 = [ "....ip6.arpa" ]; }` # `{ dn42 = [ "....ip6.arpa" ]; }`
reverseZones6 = builtins.mapAttrs (_ctx: reverseHosts6ctx: reverseZones6 = builtins.mapAttrs (ctx: reverseHosts6ctx:
builtins.attrNames ( builtins.attrNames (
builtins.foldl' (result: rname: builtins.foldl' (result: rname: result // {
result // {
"${builtins.substring ((128 - reverseZone6Size) / 2) (72 - ((128 - reverseZone6Size) / 2)) rname}" = true; "${builtins.substring ((128 - reverseZone6Size) / 2) (72 - ((128 - reverseZone6Size) / 2)) rname}" = true;
}) {} (builtins.attrNames reverseHosts6ctx) }) {} (builtins.attrNames reverseHosts6ctx)
) )
@ -172,38 +151,28 @@ rec {
in [ { in [ {
name = "zentralwerk.org"; name = "zentralwerk.org";
ns = publicNS; ns = publicNS;
records = [ { records = [];
name = "@";
type = "A";
data = publicIPv4;
} {
name = "www";
type = "A";
data = publicIPv4;
} {
name = "@";
type = "AAAA";
data = config.site.net.serv.hosts6.up4.network-homepage;
} {
name = "www";
type = "AAAA";
data = config.site.net.serv.hosts6.up4.network-homepage;
} ];
} { } {
name = "zentralwerk.dn42"; name = "zentralwerk.dn42";
ns = internalNS; ns = internalNS;
records = [ ]; records = [ {
name = "ipa";
type = "A";
data = config.site.net.serv.hosts4.ipa;
} ];
} { } {
name = "dyn.zentralwerk.org"; name = "dyn.zentralwerk.org";
ns = publicNS; ns = publicNS;
records = [ { records = [ {
name = "upstream4"; name = "upstream1";
type = "A"; type = "A";
data = publicIPv4; data = "24.134.104.53";
} {
name = "upstream2";
type = "A";
data = "24.134.252.105";
} ]; } ];
} ] } ] ++ builtins.concatLists (
++
builtins.concatLists (
builtins.attrValues ( builtins.attrValues (
builtins.mapAttrs (net: { dynamicDomain, hosts4, hosts6, extraRecords, ... }: [ builtins.mapAttrs (net: { dynamicDomain, hosts4, hosts6, extraRecords, ... }: [
{ {
@ -219,20 +188,14 @@ rec {
records = records =
hosts4Records hosts4 ++ hosts4Records hosts4 ++
lib.optionals (hosts6 ? up4) (hosts6Records hosts6.up4) ++ lib.optionals (hosts6 ? up4) (hosts6Records hosts6.up4) ++
lib.optionals (hosts6 ? flpk) (hosts6Records hosts6.flpk) ++
extraRecords; extraRecords;
dynamic = dynamicDomain; dynamic = dynamicDomain;
} }
]) namedNets ]) namedNets
) )
) ) ++ map (zone: {
++
map (zone: {
name = zone; name = zone;
ns = ns = internalNS;
if isRfc1918Reverse zone
then internalNS
else publicNS;
records = records =
map (reverse: { map (reverse: {
name = builtins.head ( name = builtins.head (
@ -244,16 +207,17 @@ rec {
builtins.filter (lib.hasSuffix ".${zone}") builtins.filter (lib.hasSuffix ".${zone}")
(builtins.attrNames reverseHosts4) (builtins.attrNames reverseHosts4)
); );
dynamic = builtins.elem zone dynamicReverseZones4; dynamic = builtins.elem zone dynamicReverseZones;
}) reverseZones4 }) reverseZones4
++ ++ builtins.concatMap (ctx:
builtins.concatMap (ctx:
map (zone: { map (zone: {
name = zone; name = zone;
ns = ns =
if ctx == "dn42" if ctx == "dn42"
then internalNS then internalNS
else publicNS; else if builtins.match "up.*" ctx != null
then publicNS
else throw "Invalid IPv6 context: ${ctx}";
records = records =
map (reverse: { map (reverse: {
name = builtins.substring 0 ((128 - reverseZone6Size) / 2 - 1) reverse; name = builtins.substring 0 ((128 - reverseZone6Size) / 2 - 1) reverse;
@ -263,7 +227,6 @@ rec {
builtins.filter (lib.hasSuffix ".${zone}") builtins.filter (lib.hasSuffix ".${zone}")
(builtins.attrNames reverseHosts6.${ctx}) (builtins.attrNames reverseHosts6.${ctx})
); );
dynamic = builtins.elem zone dynamicReverseZones6;
}) reverseZones6.${ctx} }) reverseZones6.${ctx}
) (builtins.attrNames reverseZones6); ) (builtins.attrNames reverseZones6);
} }

View File

@ -28,14 +28,8 @@ let
builtins.filter (word: builtins.filter (word:
word != [] && word != "" word != [] && word != ""
) tokens; ) tokens;
command = command = builtins.head words;
if words != [] args = builtins.tail words;
then builtins.head words
else "-";
args =
if words != []
then builtins.tail words
else [];
makeLinkFromArg = port: arg: makeLinkFromArg = port: arg:
builtins.foldl' (result: interface: builtins.foldl' (result: interface:
@ -95,9 +89,7 @@ let
ucidef_set_interfaces_lan_wan.ports = ucidef_set_interfaces_lan_wan.ports =
makeLinkFromArg "lan" (builtins.elemAt args 0) // makeLinkFromArg "lan" (builtins.elemAt args 0) //
self.lib.optionalAttrs (builtins.length args > 1) ( makeLinkFromArg "wan" (builtins.elemAt args 1);
makeLinkFromArg "wan" (builtins.elemAt args 1)
);
}; };
in in
if commands ? ${command} if commands ? ${command}

View File

@ -47,15 +47,6 @@ in
Forward true Forward true
Server "${config.site.net.serv.hosts4.spaceapi}" "${toString networkPort}" Server "${config.site.net.serv.hosts4.spaceapi}" "${toString networkPort}"
Server "${config.site.net.serv.hosts4.grafana}" "${toString networkPort}" Server "${config.site.net.serv.hosts4.grafana}" "${toString networkPort}"
Server "${config.site.net.serv.hosts4.prometheus}" "${toString networkPort}"
'';
plugins.mqtt = ''
<Publish "broker">
Host "${config.site.mqttServer.host}"
User "${config.site.mqttServer.user}"
Password "${config.site.mqttServer.password}"
ClientId "collectd-${hostName}"
</Publish>
''; '';
}) (lib.optionalAttrs (hostName != "stats") { }) (lib.optionalAttrs (hostName != "stats") {
plugins.network = '' plugins.network = ''
@ -90,7 +81,7 @@ in
Host "inbert.c3d2.de" Host "inbert.c3d2.de"
Host "heise.de" Host "heise.de"
''; '';
}) (lib.optionalAttrs config.services.kea.dhcp4.enable { }) (lib.optionalAttrs config.services.dhcpd4.enable {
plugins.exec = plugins.exec =
let let
maxTimeout = builtins.foldl' (maxTimeout: net: maxTimeout = builtins.foldl' (maxTimeout: net:
@ -104,7 +95,7 @@ in
else maxTimeout else maxTimeout
) 180 (builtins.attrNames config.site.net); ) 180 (builtins.attrNames config.site.net);
in '' in ''
Exec "${execUser}" "/run/wrappers/bin/collectd-dhcpcount" "${toString maxTimeout}" Exec "${execUser}" "${pkgs.ruby}/bin/ruby" "${./dhcpcount.rb}" "${toString maxTimeout}"
''; '';
}) (lib.optionalAttrs config.services.unbound.enable { }) (lib.optionalAttrs config.services.unbound.enable {
plugins.exec = '' plugins.exec = ''
@ -115,29 +106,4 @@ in
Exec "nobody" "${self.packages.${system}.starlink-stats}/bin/starlink-stats" "192.168.100.1:9200" Exec "nobody" "${self.packages.${system}.starlink-stats}/bin/starlink-stats" "192.168.100.1:9200"
''; '';
}) ]; }) ];
systemd.services.collectd = lib.mkIf config.services.kea.dhcp4.enable {
after = [ "kea-dhcp4-server.service" ];
};
security.wrappers = lib.mkIf config.services.kea.dhcp4.enable {
collectd-dhcpcount =
let
dhcpcount = pkgs.runCommand "dhcpcount" {
src = ./dhcpcount.rb;
buildInputs = [ pkgs.ruby ];
} ''
cp $src dhcpcount.rb
patchShebangs dhcpcount.rb
mkdir -p $out/bin
cp dhcpcount.rb $out/bin/dhcpcount
'';
in {
setuid = true;
owner = "root";
group = "root";
source = "${dhcpcount}/bin/dhcpcount";
};
};
} }

32
nix/nixos-module/collectd/dhcpcount.rb Executable file → Normal file
View File

@ -1,30 +1,38 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
require 'csv' require 'date'
INTERVAL = 60 INTERVAL = 10
TIMEOUT = ARGV[0].to_i # TODO: now unused TIMEOUT = ARGV[0].to_i
hostname = CSV::readlines("/proc/sys/kernel/hostname").join.strip hostname = IO::readlines("/proc/sys/kernel/hostname").join.strip
STDOUT.sync = true STDOUT.sync = true
loop do loop do
seen = {} seen = {}
count = 0 count = 0
now = Time.now.to_i
CSV::readlines("/var/lib/kea/kea-leases4.csv", headers: true).each do |rec| addr = nil
h = rec.to_h starts = nil
addr = h["hwaddr"]
next unless addr IO::readlines("/var/lib/dhcp/dhcpd.leases").each do |line|
last = h["expire"].to_i if line =~ /^lease (.+) \{/
elapsed = now - last addr = $1
next if elapsed >= TIMEOUT
starts = nil
elsif line =~ /starts \d+ (.+?);/
starts = DateTime.parse($1).to_time
elsif line =~ /^\}/
now = Time.now
if starts and
now >= starts and now < starts + TIMEOUT
unless seen[addr] unless seen[addr]
count += 1 count += 1
seen[addr] = true seen[addr] = true
end end
end end
end
end
puts "PUTVAL \"#{hostname}/exec-dhcpd/current_sessions-leases\" interval=#{INTERVAL} N:#{count}" puts "PUTVAL \"#{hostname}/exec-dhcpd/current_sessions-leases\" interval=#{INTERVAL} N:#{count}"
sleep INTERVAL sleep INTERVAL

0
nix/nixos-module/collectd/unbound.rb Executable file → Normal file
View File

View File

@ -1,9 +1,7 @@
# Routing daemon configuration # Routing daemon configuration
{ hostName, config, lib, pkgs, ... }: { hostName, config, options, lib, pkgs, ... }:
let let
hostNameEscaped = builtins.replaceStrings [ "-" ] [ "_" ] hostName;
hostConf = config.site.hosts.${hostName}; hostConf = config.site.hosts.${hostName};
upstreamInterfaces = lib.filterAttrs (_: { upstream, ... }: upstreamInterfaces = lib.filterAttrs (_: { upstream, ... }:
@ -12,11 +10,17 @@ let
isUpstream = upstreamInterfaces != {}; isUpstream = upstreamInterfaces != {};
ipv6RouterNets = builtins.attrNames ( # Configuring a gateway? If so, this is the associated net.
lib.filterAttrs (net: { ipv6Router, ... }: gatewayNet =
ipv6Router == hostName let
) config.site.net m = builtins.match "(.+)-gw" hostName;
); in if hostName == "c3d2-gw3"
then "c3d2"
else if m == [ "cls" ]
then "cluster"
else if m == null
then null
else builtins.head m;
enumerate = n: list: enumerate = n: list:
if list == [] if list == []
@ -65,61 +69,50 @@ in
protocol device { protocol device {
scan time 10; scan time 10;
} }
${lib.optionalString isUpstream ''
# Import address ranges of upstream interfaces so that # Import address ranges of upstream interfaces so that
# internal traffic to local public services take no detours # internal traffic to local public services take no detours
# if the default router takes another upstream gateway. # if the default router takes another upstream gateway.
protocol direct { protocol direct {
ipv4 { ipv4 {
${if isUpstream # No RFC6598
then '' import where net !~ 100.64.0.0/10
# No RFC1918, RFC6598 # No RFC1918
import where net !~ [ 100.64.0.0/10 ] && net !~ [ 10.0.0.0/8 ] && net !~ [ 172.16.0.0/12 ] && net !~ [ 192.168.0.0/16 ]; && net !~ 10.0.0.0/8
'' && net !~ 172.16.0.0/12
else ""} && net !~ 192.168.0.0/16;
}; };
ipv6; ipv6;
interface ${lib.concatMapStringsSep ", " (iface: interface ${lib.concatMapStringsSep ", " (iface:
''"${iface}"'' ''"${iface}"''
)(builtins.attrNames hostConf.interfaces)}; )(builtins.attrNames upstreamInterfaces)};
check link yes; check link yes;
} }
''}
${lib.optionalString ( ${lib.optionalString (builtins.match "anon.*" hostName != null) ''
builtins.match "anon.*" hostName != null ||
hostName == "flpk-gw"
) ''
# BIRD routing table for Wireguard transport # BIRD routing table for Wireguard transport
ipv4 table vpn_table; ipv4 table vpn4_table;
# Kernel routing table for Wireguard transport # Kernel routing table for Wireguard transport
protocol kernel VPN { protocol kernel VPN4 {
# "vpn_table" configured on anon routers # "vpn4_table" configured on anon routers
kernel table 100; kernel table 100;
ipv4 { ipv4 {
export all; export all;
table vpn_table; table vpn4_table;
}; };
} }
''} ''}
${lib.optionalString (ipv6RouterNets != []) '' ${lib.optionalString (gatewayNet != null) ''
# Router advertisements # Router advertisements
protocol radv { protocol radv {
rdnss ${config.site.net.serv.hosts6.dn42.dnscache}; rdnss ${config.site.net.serv.hosts6.dn42.dnscache};
${lib.concatMapStrings (net: '' interface "${gatewayNet}" {
interface "${net}" {
min ra interval 10; min ra interval 10;
max ra interval 60; max ra interval 60;
solicited ra unicast yes;
${if (config.site.net.${net}.dhcp.server or null) == null
then ''
# Do not use DHCP6.
managed no;
'' else ''
# Use DHCP6 for DynDNS.
managed yes;
''}
${builtins.concatStringsSep "\n" ( ${builtins.concatStringsSep "\n" (
map (subnet6: '' map (subnet6: ''
@ -127,27 +120,26 @@ in
preferred lifetime 600; preferred lifetime 600;
valid lifetime 1800; valid lifetime 1800;
}; };
'') (builtins.attrValues config.site.net.${net}.subnets6) '') (builtins.attrValues config.site.net.${gatewayNet}.subnets6)
)} )}
dnssl "${config.site.net.${net}.domainName}"; dnssl "${config.site.net.${gatewayNet}.domainName}";
}; };
'') ipv6RouterNets}
} }
''} ''}
# OSPFv2 for site-local IPv4 # OSPFv2 for site-local IPv4
protocol ospf v2 ZW4 { protocol ospf v2 ZW4 {
ipv4 { ipv4 {
import all; export where net != 0.0.0.0/0 && source != RTS_BGP;
# OSPF is self-contained
export none;
}; };
area 0 { area 0 {
${builtins.concatStringsSep "\n" ( ${builtins.concatStringsSep "\n" (
builtins.attrValues ( builtins.attrValues (
builtins.mapAttrs (net: _: builtins.mapAttrs (net: _:
# Enable OSPF only on networks with a secret. # Enable OSPF only on networks with a secret. Others
# are treated as a stubnet whose routes to
# advertise.
if config.site.net ? "${net}" && config.site.net.${net}.ospf.secret != null if config.site.net ? "${net}" && config.site.net.${net}.ospf.secret != null
then '' then ''
interface "${net}" { interface "${net}" {
@ -158,12 +150,12 @@ in
password "${config.site.net.${net}.ospf.secret}"; password "${config.site.net.${net}.ospf.secret}";
}; };
'' ''
else '' else if config.site.net ? "${net}" && config.site.net.${net}.subnet4 != null
interface "${net}" { then ''
stub yes; # Advertise route of network ${net}
cost 10; stubnet ${config.site.net.${net}.subnet4} {};
};
'' ''
else ""
) hostConf.interfaces ) hostConf.interfaces
) )
)} )}
@ -178,7 +170,7 @@ in
${lib.optionalString isUpstream '' ${lib.optionalString isUpstream ''
# OSPFv2 to advertise my default route # OSPFv2 to advertise my default route
protocol ospf v2 ZW4_${hostNameEscaped} { protocol ospf v2 ZW4_${hostName} {
ipv4 { ipv4 {
export where net = 0.0.0.0/0; export where net = 0.0.0.0/0;
}; };
@ -211,19 +203,14 @@ in
${text} ${text}
# OSPFv2 to receive a default route from ${upstream} # OSPFv2 to receive a default route from ${upstream}
protocol ospf v2 ZW4_${ protocol ospf v2 ZW4_${upstream} {
builtins.replaceStrings [ "-" ] [ "_" ] upstream
} {
ipv4 { ipv4 {
import filter { import filter {
preference = preference + ${toString (100 - n)}; preference = preference + ${toString (100 - n)};
accept; accept;
}; };
${lib.optionalString ( ${lib.optionalString (builtins.match "anon.*" hostName != null) ''
builtins.match "anon.*" hostName != null || table vpn4_table;
hostName == "flpk-gw"
) ''
table vpn_table;
''} ''}
}; };
area 0 { area 0 {
@ -232,11 +219,7 @@ in
builtins.mapAttrs (net: _: builtins.mapAttrs (net: _:
# Enable OSPF only on interfaces with a secret. # Enable OSPF only on interfaces with a secret.
lib.optionalString (config.site.net.${net}.ospf.secret != null) '' lib.optionalString (config.site.net.${net}.ospf.secret != null) ''
interface "${net}" instance ${ interface "${net}" instance ${toString config.site.hosts.${upstream}.ospf.upstreamInstance} {
builtins.replaceStrings [ "-" ] [ "_" ] (
toString config.site.hosts.${upstream}.ospf.upstreamInstance
)
} {
hello 10; hello 10;
wait 20; wait 20;
authentication cryptographic; authentication cryptographic;
@ -256,15 +239,15 @@ in
# OSPFv3 for site-local IPv6 # OSPFv3 for site-local IPv6
protocol ospf v3 ZW6 { protocol ospf v3 ZW6 {
ipv6 { ipv6 {
import all; export where net != ::/0 && source != RTS_BGP;
# OSPF is self-contained
export none;
}; };
area 0 { area 0 {
${builtins.concatStringsSep "\n" ( ${builtins.concatStringsSep "\n" (
builtins.attrValues ( builtins.attrValues (
builtins.mapAttrs (net: _: builtins.mapAttrs (net: _:
# Enable OSPF only on networks with a secret. # Enable OSPF only on networks with a secret. Others
# are treated as a stubnet whose routes to
# advertise.
if config.site.net.${net}.ospf.secret != null if config.site.net.${net}.ospf.secret != null
then '' then ''
interface "${net}" { interface "${net}" {
@ -275,12 +258,12 @@ in
password "${config.site.net.${net}.ospf.secret}"; password "${config.site.net.${net}.ospf.secret}";
}; };
'' ''
else '' else builtins.concatStringsSep "\n" (
interface "${net}" { map (subnet6: ''
stub yes; # Advertise route of network ${net}
cost 10; stubnet ${subnet6} {};
}; '') (builtins.attrValues config.site.net.${net}.subnets6)
'' )
) hostConf.physicalInterfaces ) hostConf.physicalInterfaces
) )
)} )}
@ -296,7 +279,7 @@ in
${lib.optionalString isUpstream '' ${lib.optionalString isUpstream ''
# OSPFv3 to advertise my default route # OSPFv3 to advertise my default route
protocol ospf v3 ZW6_${hostNameEscaped} { protocol ospf v3 ZW6_${hostName} {
ipv6 { ipv6 {
export where net = ::/0; export where net = ::/0;
}; };
@ -329,9 +312,7 @@ in
${text} ${text}
# OSPFv3 to receive a default route from ${upstream} # OSPFv3 to receive a default route from ${upstream}
protocol ospf v3 ZW6_${ protocol ospf v3 ZW6_${upstream} {
builtins.replaceStrings [ "-" ] [ "_" ] upstream
} {
ipv6 { ipv6 {
import filter { import filter {
preference = preference + ${toString (100 - n)}; preference = preference + ${toString (100 - n)};
@ -344,11 +325,7 @@ in
builtins.mapAttrs (net: _: builtins.mapAttrs (net: _:
# Enable OSPF only on interfaces with a secret. # Enable OSPF only on interfaces with a secret.
lib.optionalString (config.site.net.${net}.ospf.secret != null) '' lib.optionalString (config.site.net.${net}.ospf.secret != null) ''
interface "${net}" instance ${ interface "${net}" instance ${toString config.site.hosts.${upstream}.ospf.upstreamInstance} {
builtins.replaceStrings [ "-" ] [ "_" ] (
toString config.site.hosts.${upstream}.ospf.upstreamInstance
)
} {
hello 10; hello 10;
wait 20; wait 20;
authentication cryptographic; authentication cryptographic;
@ -362,7 +339,7 @@ in
} }
''; '';
n = n + 1; n = n + 1;
}) { text = ""; n = 0; } hostConf.ospf.allowedUpstreams6 }) { text = ""; n = 0; } hostConf.ospf.allowedUpstreams
).text} ).text}
# Zentralwerk DN42 # Zentralwerk DN42
@ -373,8 +350,11 @@ in
protocol static { protocol static {
ipv6; ipv6;
route fd23:42:c3d2:580::/57 unreachable; route fd23:42:c3d2:580::/57 unreachable;
# TODO: remove
route 2a02:8106:208:5200::/56 unreachable;
# TODO: remove
route 2a02:8106:211:e900::/56 unreachable;
route 2a00:8180:2c00:200::/56 unreachable; route 2a00:8180:2c00:200::/56 unreachable;
route 2a0f:5382:acab:1400::/56 unreachable;
} }
${lib.optionalString (hostConf.bgp != null) '' ${lib.optionalString (hostConf.bgp != null) ''
@ -436,8 +416,8 @@ in
]; ];
}; };
instance = { instance = {
ipv4 = "ZW4_${hostNameEscaped}"; ipv4 = "ZW4_${hostName}";
ipv6 = "ZW6_${hostNameEscaped}"; ipv6 = "ZW6_${hostName}";
}; };
checkService = addressFamily: { checkService = addressFamily: {
description = "Check connectivity for ${addressFamily}"; description = "Check connectivity for ${addressFamily}";
@ -447,7 +427,7 @@ in
User = "bird2"; User = "bird2";
Group = "bird2"; Group = "bird2";
}; };
path = with pkgs; [ bird2 iputils ]; path = [ pkgs.bird2 "/run/wrappers" ];
script = '' script = ''
STATE=unknown STATE=unknown

View File

@ -1,4 +1,4 @@
{ config, lib, modulesPath, pkgs, ... }: { config, lib, modulesPath, ... }:
{ {
imports = [ imports = [
@ -6,19 +6,22 @@
(modulesPath + "/virtualisation/lxc-container.nix") (modulesPath + "/virtualisation/lxc-container.nix")
]; ];
environment = { boot = {
etc."machine-id".text = builtins.substring 0 8 (builtins.hashString "sha256" config.networking.hostName); isContainer = true;
systemPackages = with pkgs; [ loader = {
ripgrep initScript.enable = true;
]; };
}; };
environment.etc."machine-id".text =
builtins.substring 0 8 (
builtins.hashString "sha256" config.networking.hostName
);
nix = { nix = {
settings = { useSandbox = false;
sandbox = false; maxJobs = lib.mkDefault 1;
max-jobs = lib.mkDefault 4; buildCores = lib.mkDefault 1;
cores = lib.mkDefault 4;
};
}; };
systemd.services = systemd.services =

View File

@ -1,5 +1,5 @@
# ISC DHCP/IPv4 server configuration # ISC DHCP/IPv4 server configuration
{ hostName, config, lib, ... }: { hostName, inputs, config, lib, ... }:
let let
dhcpNets = dhcpNets =
@ -8,341 +8,81 @@ let
dhcp.server == hostName dhcp.server == hostName
) config.site.net; ) config.site.net;
concatMapDhcpNets = f:
lib.pipe dhcpNets [
(builtins.mapAttrs f)
builtins.attrValues
(map (r: if builtins.isList r then r else [ r ]))
builtins.concatLists
];
enabled = builtins.length (builtins.attrNames dhcpNets) > 0; enabled = builtins.length (builtins.attrNames dhcpNets) > 0;
in in
{ {
services.kea.dhcp4 = lib.mkIf enabled { services.dhcpd4 = lib.optionalAttrs enabled {
enable = true; enable = true;
settings = { interfaces = builtins.attrNames dhcpNets;
interfaces-config.interfaces = builtins.attrNames dhcpNets;
dhcp-ddns.enable-updates = true;
ddns-send-updates = true;
# TODO: use with kea >= 2.5.0
# ddns-conflict-resolution-mode = "check-exists-with-dhcid";
ddns-use-conflict-resolution = false;
ddns-replace-client-name = "when-not-present";
expired-leases-processing.hold-reclaimed-time = builtins.foldl' lib.max
3600 (concatMapDhcpNets (net: { dhcp, ... }: dhcp.max-time));
subnet4 = concatMapDhcpNets (net: { vlan, subnet4, hosts4, dhcp, domainName, captiveJson, ... }: { extraConfig = ''
id = vlan; ${builtins.concatStringsSep "\n" (
subnet = subnet4;
pools = [ {
pool = "${dhcp.start} - ${dhcp.end}";
} ];
renew-timer = builtins.ceil (.5 * dhcp.time);
rebind-timer = builtins.ceil (.85 * dhcp.time);
valid-lifetime = dhcp.time;
option-data = [ {
space = "dhcp4";
name = "routers";
code = 3;
data = config.site.net.${net}.hosts4.${dhcp.router};
} {
space = "dhcp4";
name = "domain-name";
code = 15;
data = domainName;
} {
space = "dhcp4";
name = "domain-name-servers";
code = 6;
data = "${config.site.net.serv.hosts4.dnscache}, 9.9.9.9";
} ] ++ lib.optional (captiveJson != null) {
space = "dhcp4";
name = "v4-captive-portal";
code = 114;
data = captiveJson;
};
ddns-qualifying-suffix = domainName;
reservations = lib.pipe dhcp.fixed-hosts [
(builtins.mapAttrs (fixedAddr: hwaddr:
if hosts4 ? ${fixedAddr}
then # fixedAddr is a known hostname
let
name = fixedAddr;
addr = hosts4.${fixedAddr};
in {
hostname = "${name}.${net}.zentralwerk.org";
hw-address = hwaddr;
ip-address = addr;
}
else
let
names = builtins.attrNames (
lib.filterAttrs (_: hostAddr:
hostAddr == fixedAddr
) hosts4);
name = builtins.head names;
in
if builtins.length names > 0
then { # fixedAddr is IPv4 of a known hostname
hostname = "${name}.${net}.zentralwerk.org";
hw-address = hwaddr;
ip-address = hosts4.${name};
} # fixedAddr is IPv4?
else {
hw-address = hwaddr;
ip-address = fixedAddr;
}
))
builtins.attrValues
(builtins.filter (r: r != null))
];
});
match-client-id = false;
host-reservation-identifiers = [ "hw-address" ];
# Netbooting
option-def = [ {
name = "PXEDiscoveryControl";
code = 6;
space = "vendor-encapsulated-options-space";
type = "uint8";
array = false;
} {
name = "PXEMenuPrompt";
code = 10;
space = "vendor-encapsulated-options-space";
type = "record";
array = false;
record-types = "uint8,string";
} {
name = "PXEBootMenu";
code = 9;
space = "vendor-encapsulated-options-space";
type = "record";
array = false;
record-types = "uint16,uint8,string";
} ];
client-classes =
let
rpi4Class = {
name = "rpi4-pxe";
test = "option[vendor-class-identifier].text == 'PXEClient:Arch:00000:UNDI:002001'";
option-data = [ {
name = "boot-file-name";
data = "bootcode.bin";
} {
name = "vendor-class-identifier";
data = "PXEClient";
} {
name = "vendor-encapsulated-options";
} {
name = "PXEBootMenu";
csv-format = true;
data = "0,17,Raspberry Pi Boot";
space = "vendor-encapsulated-options-space";
} {
name = "PXEDiscoveryControl";
data = "3";
space = "vendor-encapsulated-options-space";
} {
name = "PXEMenuPrompt";
csv-format = true;
data = "0,PXE";
space = "vendor-encapsulated-options-space";
} ];
};
pxeClassData = {
PXE-Legacy = {
arch = "00000";
boot-file-name = "netboot.xyz.kpxe";
};
PXE-UEFI-32-1.arch = "00002";
PXE-UEFI-32-2.arch = "00006";
PXE-UEFI-64-1.arch = "00007";
PXE-UEFI-64-2.arch = "00008";
PXE-UEFI-64-3.arch = "00009";
};
makePxe = name: { boot-file-name ? "netboot.xyz.efi", arch }: {
inherit name boot-file-name;
test = "substring(option[60].hex,0,20) == 'PXEClient:Arch:${arch}'";
next-server = config.site.net.serv.hosts4.nfsroot;
};
in
[ rpi4Class ]
++
builtins.attrValues ( builtins.attrValues (
builtins.mapAttrs makePxe pxeClassData builtins.mapAttrs (net: { dhcp, subnet4Net, subnet4Len, domainName, ...}:
); ''
ddns-update-style standard;
control-socket = { key dyndns {
socket-type = "unix"; algorithm hmac-sha256;
socket-name = "/run/kea/dhcp4-socket"; secret ${config.site.dyndnsKey};
}; };
hooks-libraries = [ { zone ${domainName}. {
library = "/run/current-system/sw/lib/kea/hooks/libdhcp_stat_cmds.so"; primary ${config.site.net.serv.hosts4.dns};
} { primary6 ${config.site.net.serv.hosts6.dn42.dns};
library = "/run/current-system/sw/lib/kea/hooks/libdhcp_lease_cmds.so"; key dyndns;
} ];
};
};
services.kea.dhcp6 = lib.mkIf enabled {
enable = true;
settings = {
interfaces-config.interfaces = builtins.attrNames dhcpNets;
dhcp-ddns.enable-updates = true;
ddns-override-no-update = true;
ddns-override-client-update = true;
ddns-replace-client-name = "when-not-present";
# TODO: use with kea >= 2.5.0
# ddns-conflict-resolution-mode = "check-exists-with-dhcid";
ddns-use-conflict-resolution = false;
subnet6 = concatMapDhcpNets (net: { vlan, subnets6, dhcp, domainName, captiveJson, ... }:
let
subnet = subnets6.up4 or subnets6.flpk or null;
prefix = builtins.head (builtins.split "::/" subnet);
in
if subnet != null
then {
id = vlan;
interface = net;
inherit subnet;
pools = [ {
pool = "${prefix}:c3d2:c3d2:c3d2:1000 - ${prefix}:c3d2:c3d2:c3d2:ffff";
#pool = subnet;
} ];
valid-lifetime = dhcp.time;
max-valid-lifetime = dhcp.max-time;
option-data = [ {
space = "dhcp6";
name = "domain-search";
code = 24;
data = domainName;
} {
space = "dhcp6";
name = "dns-servers";
code = 23;
data = "${config.site.net.serv.hosts6.dn42.dnscache}, 2620:fe::9";
} ] ++ lib.optional (captiveJson != null) {
space = "dhcp6";
name = "v6-captive-portal";
code = 103;
data = captiveJson;
};
ddns-generated-prefix = "d";
ddns-qualifying-suffix = domainName;
} }
else [] ${lib.concatMapStrings ({ name, dynamic, ... }:
); lib.optionalString (
host-reservation-identifiers = [ "hw-address" ];
#reservations = concatMapDhcpNets (net: { hosts6, dhcp, ... }:
# builtins.filter (r: r != null) (
# builtins.attrValues (
# builtins.mapAttrs (name: hwaddr:
# let
# ip-addresses = lib.pipe hosts6 [
# (builtins.mapAttrs (_: hosts6: hosts6.${name} or null))
# builtins.attrValues
# (builtins.filter (a: a != null))
# ];
# in
# if builtins.trace (lib.generators.toPretty {} ip-addresses) (builtins.length ip-addresses) > 0
# then {
# hostname = "${name}.${net}.zentralwerk.org";
# hw-address = hwaddr;
# inherit ip-addresses;
# }
# else null
# ) dhcp.fixed-hosts
# )));
control-socket = {
socket-type = "unix";
socket-name = "/run/kea/dhcp6.socket";
};
hooks-libraries = [ {
library = "/run/current-system/sw/lib/kea/hooks/libdhcp_stat_cmds.so";
} {
library = "/run/current-system/sw/lib/kea/hooks/libdhcp_lease_cmds.so";
} ];
};
};
services.kea.dhcp-ddns = lib.mkIf enabled {
enable = true;
settings = {
tsig-keys = [ {
name = "dyndns";
algorithm = "hmac-sha256";
secret = config.site.dyndnsKey;
} ];
forward-ddns.ddns-domains = concatMapDhcpNets (net: { domainName, ... }: {
name = "${domainName}.";
key-name = "dyndns";
dns-servers = [ {
ip-address = config.site.net.serv.hosts4.dns;
} {
ip-address = config.site.net.serv.hosts6.dn42.dns;
} ];
});
reverse-ddns.ddns-domains = map ({ name, ...}: {
name = "${name}.";
key-name = "dyndns";
dns-servers = [ {
ip-address = config.site.net.serv.hosts4.dns;
} {
ip-address = config.site.net.serv.hosts6.dn42.dns;
} ];
}) (
builtins.filter ({ name, dynamic, ... }:
dynamic && dynamic &&
(lib.hasSuffix ".in-addr.arpa" name || lib.hasSuffix ".in-addr.arpa" name
lib.hasSuffix ".ip6.arpa" name) ) ''
) config.site.dns.localZones zone ${name}. {
); primary ${config.site.net.serv.hosts4.dns};
control-socket = { primary6 ${config.site.net.serv.hosts6.dn42.dns};
socket-type = "unix"; key dyndns;
socket-name = "/run/kea/dhcp-ddns.socket"; }
}; ''
}; ) config.site.dns.localZones}
};
services.kea.ctrl-agent = lib.mkIf enabled { option arch code 93 = unsigned integer 16;
enable = true; group {
settings.control-sockets = { default-lease-time ${toString dhcp.time};
dhcp4 = { max-lease-time ${toString dhcp.max-time};
socket-type = "unix"; option routers ${config.site.net.${net}.hosts4.${builtins.replaceStrings [".${net}"] [""] dhcp.router}};
socket-name = "/run/kea/dhcp4.socket"; option domain-name "${domainName}";
}; option domain-name-servers 172.20.73.8, 9.9.9.9;
dhcp6 = { ddns-domainname "${domainName}";
socket-type = "unix";
socket-name = "/run/kea/dhcp6.socket";
};
d2 = {
socket-type = "unix";
socket-name = "/run/kea/dhcp-ddns.socket";
};
};
};
# Increase reliablity next-server ${config.site.net.serv.hosts4.netboot};
# (mostly for kea-dhcp-ddns-server.service) if option arch = 00:00 {
systemd.services = filename "netboot.xyz.kpxe";
let } else {
restartService.serviceConfig = { filename "netboot.xyz.efi";
RestartSec = 4; }
Restart = "always";
}; subnet ${subnet4Net} netmask ${lib.netmasks.${toString subnet4Len}} {
in { range ${dhcp.start} ${dhcp.end};
kea-dhcp4-server = restartService; }
kea-dhcp6-server = restartService;
kea-dhcp-ddns-server = restartService; update-static-leases on;
${builtins.concatStringsSep "\n" (
builtins.attrValues (
builtins.mapAttrs (addr: hwaddr:
''
host ${addr} {
hardware ethernet ${hwaddr};
fixed-address ${addr};
}
''
) dhcp.fixed-hosts
)
)}
}
''
) dhcpNets
)
)}
'';
}; };
} }

View File

@ -1,30 +1,33 @@
{ config, dns-nix, hostName, lib, pkgs, self, ... }: { hostName, config, lib, pkgs, self, inputs, ... }:
let let
serial = builtins.substring 0 10 self.lastModifiedDate; serial =
let
generateZoneFile = let timestamp = toString self.lastModified;
util = dns-nix.util.${pkgs.system}; datePkg = pkgs.runCommandLocal "date-${timestamp}" {} ''
in { name, ns, records, ... }: (util.writeZone name { date -d @${timestamp} +%Y%m%d%H > $out
TTL = 60*60; '';
SOA = { in
nameServer = "${lib.dns.ns}."; toString (import datePkg);
adminEmail = "astro@spaceboyz.net";
serial = lib.toInt serial; generateZoneFile = { name, ns, records, dynamic }:
refresh = 1*60*60; builtins.toFile "${name}.zone" ''
retry = 5*60; $ORIGIN ${name}.
expire = 2*60*60; $TTL 1h
minimum = 1*60;
}; @ IN SOA ${lib.dns.ns}. astro.spaceboyz.net. (
NS = map (a: a+".") ns; ${serial} ; serial
subdomains = lib.foldl (a: b: lib.recursiveUpdate a b) { } (map ({ name, type, data }: { 1h ; refresh
${name}.${type} = [ data ]; 1m ; retry
}) records); 2h ; expire
}).overrideAttrs (_: { 1m ; minimum
checkPhase = '' )
${pkgs.knot-dns}/bin/kzonecheck "$target" ${lib.concatMapStrings (ns: " IN NS ${ns}.\n") ns}
${lib.concatMapStrings ({ name, type, data }:
"${name} IN ${type} ${data}\n"
) records}
''; '';
});
in in
{ {
options = options =
@ -39,7 +42,7 @@ in
type = types.enum [ "A" "AAAA" "MX" "SRV" "CNAME" "TXT" "PTR" ]; type = types.enum [ "A" "AAAA" "MX" "SRV" "CNAME" "TXT" "PTR" ];
}; };
data = mkOption { data = mkOption {
type = types.oneOf [ types.str (types.attrsOf (types.oneOf [ types.int types.str ]))]; type = types.str;
}; };
}; };
@ -73,169 +76,90 @@ in
config = { config = {
site.dns.localZones = lib.dns.localZones; site.dns.localZones = lib.dns.localZones;
services.knot = lib.mkIf config.site.hosts.${hostName}.services.dns.enable ( services.bind = lib.mkIf config.site.hosts.${hostName}.services.dns.enable (
let let
generateZone = zone@{ name, dynamic, ... }: { generateZone = zone@{ name, dynamic, ... }: {
domain = name; inherit name;
template = "zentralwerk"; master = true;
acl = [ "zone_xfr" ] # allowed for zone-transfer
++ lib.optional (lib.hasSuffix ".arpa" name) "dn42" slaves = [
++ lib.optional dynamic "dyndns"; # ns.c3d2.de
file = if dynamic "217.197.84.53" "2001:67c:1400:2240::a"
then "/var/lib/knot/zones/${name}.zone" config.site.net.serv.hosts4.bind
config.site.net.serv.hosts6.dn42.bind
config.site.net.serv.hosts6.up4.bind
# ns.spaceboyz.net
"172.22.24.4" "2a01:4f9:4b:39ec::4"
];
file =
if dynamic
then "/var/db/bind/${name}.zone"
else generateZoneFile zone; else generateZoneFile zone;
notify = [ "all" ]; extraConfig = ''
also-notify {
# ns.c3d2.de
217.197.84.53;
2001:67c:1400:2240::a;
${config.site.net.serv.hosts4.bind};
${config.site.net.serv.hosts6.dn42.bind};
${config.site.net.serv.hosts6.up4.bind};
# ns.spaceboyz.net
172.22.24.4;
95.217.229.209;
2a01:4f9:4b:39ec::4;
};
notify-source ${config.site.net.serv.hosts4.dns};
notify-source-v6 ${config.site.net.serv.hosts6.up4.dns};
'' + lib.optionalString dynamic ''
allow-update { key "dyndns"; };
'';
}; };
in { in {
enable = true; enable = true;
settings = { zones = map generateZone config.site.dns.localZones;
acl = [
{
id = "dyndns";
action = "update";
key = "dyndns";
}
{
id = "zone_xfr";
address = with config.site.net.serv; [
# ns.c3d2.de
hosts4.knot hosts6.dn42.knot hosts6.up4.knot
"2a00:8180:2c00:282:2041:cbff:fe0c:8516"
"fd23:42:c3d2:582:2041:cbff:fe0c:8516"
# ns.spaceboyz.net
"172.22.24.4" "37.27.116.148" "2a01:4f9:3070:2728::4"
# ns1.supersandro.de
"188.34.196.104" "2a01:4f8:1c1c:1d38::1"
];
action = "transfer";
}
{
id = "dn42";
address = [ "172.22.24.4" "fd42:180:3de0:30::1" ];
}
];
key = [ { extraConfig = ''
id = "dyndns"; key "dyndns" {
algorithm = "hmac-sha256"; algorithm hmac-sha256;
secret = config.site.dyndnsKey; secret "${config.site.dyndnsKey}";
} ];
log = [ {
target = "syslog";
any = "info";
} ];
mod-stats = [ {
id = "default";
query-type = "on";
} ];
remote = let
via = with config.site.net.serv; [ hosts4.dns hosts6.up4.dns ];
in [
{
id = "ns.c3d2.de";
address = with config.site.net.serv; [ hosts4.knot hosts6.dn42.knot hosts6.up4.knot ];
inherit via;
} {
id = "ns.spaceboyz.net";
address = [
"172.22.24.4"
"37.27.116.148" "2a01:4f9:3070:2728::4"
];
inherit via;
} {
id = "ns1.supersandro.de";
address = [ /*"188.34.196.104"*/ "2a01:4f8:1c1c:1d38::1" ];
inherit via;
} {
id = "b.master.delegation-servers.dn42";
address = [ "172.22.24.4" "fd42:180:3de0:30::1" ];
}
];
remotes = [
{
id = "all";
remote = [ "ns.c3d2.de" "ns.spaceboyz.net" "ns1.supersandro.de" ];
}
{
id = "dn42";
remote = [ "b.master.delegation-servers.dn42" ];
}
];
server = {
answer-rotation = true;
automatic-acl = true;
identity = "dns.serv.zentralwerk.org";
listen = with config.site.net; [
"127.0.0.1" "::1"
serv.hosts4.dns serv.hosts6.up4.dns serv.hosts6.dn42.dns
];
tcp-fastopen = true;
version = null;
};
template = [
{
# default is a magic name and is always loaded.
# Because we want to use catalog-role/catalog-zone settings for all zones *except* the catalog zone itself, we must split the templates
id = "default";
global-module = [ "mod-stats" ];
}
{
id = "zentralwerk";
catalog-role = "member";
catalog-zone = "zentralwerk.";
dnssec-signing = true;
journal-content = "all"; # required for zonefile-load=difference-no-serial and makes cold starts like zone reloads
module = "mod-stats/default";
semantic-checks = true;
serial-policy = "increment";
storage = "/var/lib/knot/zones";
zonefile-load = "difference-no-serial";
}
];
zone = [ {
acl = "zone_xfr";
catalog-role = "generate";
domain = "zentralwerk.";
notify = [ "ns1.supersandro.de" "ns.spaceboyz.net" ];
storage = "/var/lib/knot/catalog";
} ] ++ map generateZone config.site.dns.localZones;
}; };
'';
extraOptions = ''
# allow underscores in dynamic hostnames
${lib.concatMapStringsSep "\n" (type: ''
check-names ${type} ignore;
'') [ "master" "slave" "response" ]}
'';
}); });
systemd.services = { systemd.services.create-dynamic-zones = {
create-dynamic-zones = {
description = "Creates dynamic zone files"; description = "Creates dynamic zone files";
requiredBy = [ "knot.service" ]; requiredBy = [ "bind.service" ];
before = [ "knot.service" ]; before = [ "bind.service" ];
serviceConfig.Type = "oneshot"; serviceConfig.Type = "oneshot";
script = '' script = ''
mkdir -p /var/lib/knot/zones mkdir -p /var/db/bind
${lib.concatMapStringsSep "\n" (zone@{ name, ... }: '' ${lib.concatMapStringsSep "\n" (zone@{ name, ... }: ''
[ -e /var/lib/knot/zones/${name}.zone ] || \ [ -e /var/db/bind/${name}.zone ] || \
cp ${generateZoneFile zone} /var/lib/knot/zones/${name}.zone cp ${generateZoneFile zone} /var/db/bind/${name}.zone
chown -R knot /var/lib/knot/zones chown -R named /var/db/bind
chmod -R u+rwX /var/lib/knot/zones chmod -R u+rwX /var/db/bind
'') (builtins.filter ({ dynamic, ... }: dynamic) config.site.dns.localZones)} '') (
builtins.filter ({ dynamic, ... }: dynamic) config.site.dns.localZones
)}
''; '';
}; };
systemd.services.update-dynamic-zones = {
update-dynamic-zones = {
description = "Creates initial records in dynamic zone files"; description = "Creates initial records in dynamic zone files";
requiredBy = [ "knot.service" ]; requiredBy = [ "bind.service" ];
after = [ "knot.service" ]; after = [ "bind.service" ];
serviceConfig.Type = "oneshot"; serviceConfig.Type = "oneshot";
path = [ pkgs.dnsutils ]; path = [ pkgs.dnsutils ];
script = lib.concatMapStrings (zone: '' script = ''
nsupdate -v -y "hmac-sha256:dyndns:${config.site.dyndnsKey}" <<EOF ${lib.concatMapStrings (zone: ''
nsupdate -y "hmac-sha256:dyndns:${config.site.dyndnsKey}" <<EOF
server localhost server localhost
${lib.concatMapStringsSep "\n" ({ name, type, data }: '' ${lib.concatMapStringsSep "\n" ({ name, type, data }: ''
@ -245,8 +169,10 @@ in
send send
EOF EOF
'') (builtins.filter ({ dynamic, ... }: dynamic) config.site.dns.localZones); '') (
}; builtins.filter ({ dynamic, ... }: dynamic) config.site.dns.localZones
)}
'';
}; };
}; };
} }

View File

@ -1,99 +1,105 @@
{ hostName, config, lib, pkgs, ... }: { hostName, config, lib, pkgs, ... }:
lib.mkIf config.site.hosts.${hostName}.services.dnscache.enable { lib.mkIf config.site.hosts.${hostName}.services.dnscache.enable {
services.kresd = { services.unbound = {
enable = true; enable = true;
instances = 4; settings = {
listenPlain = [ "0.0.0.0:53" "[::0]:53" ]; remote-control = {
package = pkgs.knot-resolver.override { extraFeatures = true; }; control-enable = true;
extraConfig = /* lua */ '' control-use-cert = false;
modules = { };
'http', server = {
'policy', num-threads = 4;
'predict', verbosity = 1;
'prefill', prefetch = true;
'serve_stale < cache', -- servce stail records while refreshing the record serve-expired = true;
'workarounds < iterate', -- solve problems around specific broken subdomains, mainly disables case randomization cache-min-ttl = 60;
'view' cache-max-ttl = 3600;
}
cache.size = 500 * MB interface = [ "0.0.0.0" "'::0'" ];
cache.min_ttl(60) # TODO: generate
access-control = [
"fd23:42:c3d2:500::/56 allow"
# TODO: remove
"2a02:8106:208:5200::/56 allow"
# TODO: remove
"2a02:8106:211:e900::/56 allow"
"2a00:8180:2000:37::1/128 allow"
"2a00:8180:2c00:200::/56 allow"
"::172.20.72.0/117 allow"
"::172.22.99.0/120 allow"
"::1/128 allow"
"172.20.72.0/21 allow"
"10.0.0.0/24 allow"
"10.200.0.0/15 allow"
"172.22.99.0/24 allow"
"127.0.0.0/8 allow"
"0.0.0.0/0 deny"
"::/0 deny"
];
# For DNS over TLS
tls-cert-bundle = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
net.listen('127.0.0.1', 8453, { kind = 'webmgmt' }) # allow reverse lookup of rfc1918 space, which includes the DN42 address space
http.prometheus.namespace = 'resolver_' unblock-lan-zones = true;
insecure-lan-zones = true;
-- dns42 domain-insecure = [
policy.add(policy.suffix( "dn42"
policy.STUB({'fd42:d42:d42:54::1', 'fd42:d42:d42:53::1', '172.20.0.53', '172.23.0.53'}), "d.f.ip6.arpa"
policy.todnames({'dn42.', 'd.f.ip6.arpa', '20.172.in-addr.arpa', '21.172.in-addr.arpa', '22.172.in-addr.arpa', '23.172.in-addr.arpa'}) "ffdd"
)) ];
};
-- freifunk forward-zone = let
policy.add(policy.suffix( mkFfddZone = name: {
policy.STUB({'10.200.0.4', '10.200.0.16'}), inherit name;
policy.todnames({'ffdd.', '200.10.in-addr.arpa', '201.10.in-addr.arpa'}) forward-addr = [ "10.200.0.4" "10.200.0.16" ];
)) };
in [ {
-- size.dns.localZones name = ".";
policy.add(policy.suffix( forward-tls-upstream = true;
policy.STUB({'${config.site.net.serv.hosts4.dns}', ${lib.concatStringsSep ", " (map (hosts6: "'${hosts6.dns}'") (builtins.attrValues config.site.net.serv.hosts6))}}), forward-addr = [
policy.todnames({${lib.concatStringsSep ", " (map (zone: "'${zone.name}'") config.site.dns.localZones)}}) # Quad9
)) "2620:fe::fe@853#dns.quad9.net"
"9.9.9.9@853#dns.quad9.net"
-- forward to dns caches "2620:fe::9@853#dns.quad9.net"
policy.add(policy.slice( "149.112.112.112@853#dns.quad9.net"
policy.slice_randomize_psl(), # Cloudflare DNS
-- quad9 "2606:4700:4700::1111@853#cloudflare-dns.com"
policy.TLS_FORWARD({ "1.1.1.1@853#cloudflare-dns.com"
{'2620:fe::fe', hostname='dns.quad9.net'}, "2606:4700:4700::1001@853#cloudflare-dns.com"
{'2620:fe::9', hostname='dns.quad9.net'}, "1.0.0.1@853#cloudflare-dns.com"
{'9.9.9.9', hostname='dns.quad9.net'}, ];
{'149.112.112.112', hostname='dns.quad9.net'} } ] ++
}), # Local networks
-- cloudflare map ({ name, ... }: {
policy.TLS_FORWARD({ name = "${name}";
{'2606:4700:4700::1111', hostname='cloudflare-dns.com'}, forward-addr = [ "${config.site.net.serv.hosts4.dns}" ] ++
{'2606:4700:4700::1001', hostname='cloudflare-dns.com'}, map (hosts6: hosts6.dns)
{'1.1.1.1', hostname='cloudflare-dns.com'}, (builtins.attrValues config.site.net.serv.hosts6);
{'1.0.0.1', hostname='cloudflare-dns.com'} }) config.site.dns.localZones
}) # Freifunk
)) ++ (map mkFfddZone [
"ffdd"
-- allow access from our networks "200.10.in-addr.arpa"
'' + lib.concatMapStringsSep "\n" (cidr: "view:addr('${cidr}', policy.all(policy.PASS))") [ "201.10.in-addr.arpa"
# localhost ]);
"::1/128" "127.0.0.0/8" # DN42
# mgmt stub-zone = let
"${config.site.net.mgmt.subnet4}" mkDn42Zone = name: {
# dn42 inherit name;
"fd23:42:c3d2:500::/56" "::172.20.72.0/117" "::172.22.99.0/120" stub-prime = true;
"172.20.72.0/21" "172.22.99.0/24" stub-addr = [
# freifunk "172.20.0.53" "fd42:d42:d42:54::1"
"10.200.0.0/15" "172.23.0.53" "fd42:d42:d42:53::1"
# DSI ];
"2a00:8180:2000:37::1/128" "2a00:8180:2c00:200::/56" };
# flpk in map mkDn42Zone [
"${config.site.net.flpk.subnet4}" "2a0f:5382:acab:1400::/56 allow" "dn42" "d.f.ip6.arpa"
] + "\n" + /* lua */ '' "20.172.in-addr.arpa" "21.172.in-addr.arpa"
"22.172.in-addr.arpa" "23.172.in-addr.arpa"
-- drop everything that hasn't matched ];
view:addr('0.0.0.0/0', policy.all(policy.DROP)) };
view:addr('::/0', policy.all(policy.DROP))
predict = {
window = 15, -- sampling window
period = 24*(60/15) -- track last X hours, divide through sampling window
}
prefill.config({
['.'] = {
url = 'https://www.internic.net/domain/root.zone',
interval = 86400, -- seconds
}
})
trust_anchors.set_insecure({'dn42', 'd.f.ip6.arpa', 'ffdd'})
'';
}; };
} }

View File

@ -1,114 +0,0 @@
{ config, lib, ... }:
let
inherit (config.networking) hostName;
interfaces = config.site.hosts.${hostName}.physicalInterfaces;
# linux iface name max length = 15
shortenNetName = name:
if builtins.match "priv(.*)" name != null
then "p" + builtins.substring 4 9 name
else if name == "coloradio"
then "cr"
else if name == "coloradio-gw"
then "cr-gw"
else name;
checkIfname = ifname: let
len = builtins.stringLength ifname;
in if len > 15
then throw "Interface name ${ifname} is ${toString (len - 15)} chars too long."
else ifname;
# `lxc.net.*` formatter for lxc.container.conf files
netConfig =
let
attrNamesOrdered = attrs:
if attrs ? type
then [ "type" ] ++ lib.remove "type" (builtins.attrNames attrs)
else builtins.attrNames attrs;
serialize = name: x:
if builtins.isString x
then "${name} = ${x}\n"
else if builtins.isAttrs x
then builtins.concatStringsSep "" (
map (n: serialize "${name}.${n}" x.${n}) (attrNamesOrdered x)
)
else if builtins.isList x
then
let
enumerate = xs: n:
if xs == []
then []
else [ {
e = builtins.head xs;
i = n;
} ] ++ enumerate (builtins.tail xs) (n + 1);
in
builtins.concatStringsSep "" (
map ({ e, i }: serialize "${name}.${toString i}" e) (enumerate x 0)
)
else throw "Invalid data in lxc net config for ${name}: ${lib.generators.toPretty {} x}";
in
serialize "lxc.net" (
map (netName:
let
ifData = interfaces.${netName};
in {
type = ifData.type;
name = checkIfname netName;
flags = "up";
hwaddr = if ifData ? hwaddr && ifData.hwaddr != null
then ifData.hwaddr
else "0A:14:48:xx:xx:xx";
} // (lib.optionalAttrs (ifData.type == "veth") {
veth.pair = checkIfname "${shortenNetName hostName}-${shortenNetName netName}";
veth.mode = checkIfname "bridge";
link = checkIfname netName;
}) // (lib.optionalAttrs (ifData.type == "phys") {
link = checkIfname "ext-${netName}";
})
) (builtins.attrNames interfaces)
);
in
{
system.build.lxcConfig = builtins.toFile "${hostName}.conf" ''
# For lxcfs and sane defaults
lxc.include = /etc/lxc/common.conf
lxc.uts.name = ${hostName}
# Handled by lxc@.service
lxc.start.auto = 0
lxc.rootfs.path = /var/lib/lxc/${hostName}/rootfs
lxc.init.cmd = "/init"
lxc.mount.entry = /nix/store nix/store none bind,ro 0 0
lxc.mount.entry = none tmp tmpfs defaults 0 0
lxc.mount.auto = proc:mixed sys:ro cgroup:mixed
lxc.autodev = 1
lxc.tty.max = 0
lxc.pty.max = 8
lxc.cap.drop = sys_module sys_time sys_nice sys_pacct sys_rawio
security.privileged = false
lxc.apparmor.profile = lxc-container-default-with-mounting
lxc.cgroup.memory.limit_in_bytes = 1G
lxc.cgroup.memory.kmem.tcp.limit_in_bytes = 128M
# tuntap
lxc.cgroup.devices.allow = c 10:200 rw
lxc.cgroup2.devices.allow = c 10:200 rw
# ppp
lxc.cgroup.devices.allow = c 108:0 rwm
lxc.cgroup2.devices.allow = c 108:0 rwm
${netConfig}
'';
}

View File

@ -0,0 +1,22 @@
{ lib, pkgs, ... }:
let
netboot_xyz_efi = pkgs.fetchurl {
url = "https://github.com/netbootxyz/netboot.xyz/releases/download/2.0.40/netboot.xyz.efi";
sha256 = "1gvgvlaxhjkr9i0b2bjq85h12ni9h5fn6r8nphsag3il9kificcc";
};
netboot_xyz_kpxe = pkgs.fetchurl {
url = "https://github.com/netbootxyz/netboot.xyz/releases/download/2.0.40/netboot.xyz.kpxe";
sha256 = "1crkr995i1hv3q548gx2xan1ymxmzcnr7mxaf77s2410mpqfcx82";
};
tftpRoot = pkgs.runCommand "tftproot" {} ''
mkdir -p $out
ln -s ${netboot_xyz_efi} $out/netboot.xyz.efi
ln -s ${netboot_xyz_kpxe} $out/netboot.xyz.kpxe
'';
in
{
services.atftpd = {
enable = true;
root = tftpRoot;
};
}

View File

@ -1,4 +1,4 @@
{ hostName, config, lib, pkgs, ... }: { hostName, config, lib, ... }:
let let
hostConf = config.site.hosts.${hostName}; hostConf = config.site.hosts.${hostName};
@ -15,8 +15,6 @@ let
else null; else null;
enabled = firstUpstreamInterface != null; enabled = firstUpstreamInterface != null;
inherit (upstreamInterfaces.${firstUpstreamInterface}.upstream) staticIpv4Address;
in in
{ {
systemd.network.networks = { systemd.network.networks = {
@ -24,23 +22,19 @@ in
# systemd-networkd only requests Prefix Delegation via DHCPv6 on # systemd-networkd only requests Prefix Delegation via DHCPv6 on
# the upstream interface if another interface is configured for it. # the upstream interface if another interface is configured for it.
# without this, the static ipv6 subnet won't be routed to us. # without this, the static ipv6 subnet won't be routed to us.
networkConfig.DHCPPrefixDelegation = true; networkConfig.DHCPv6PrefixDelegation = true;
dhcpV6PrefixDelegationConfig = { dhcpV6PrefixDelegationConfig = {
SubnetId = "81"; SubnetId = "81";
# because we have static addresses, we don't actually use this # because we have static addresses, we don't actually use this
Assign = false; Assign = false;
}; };
}; };
} // builtins.mapAttrs (_: { upstream, ... }: } // builtins.mapAttrs (_: { upstream, ... }: {
# DHCP
lib.optionalAttrs (hostName != "flpk-gw") {
DHCP = "yes"; DHCP = "yes";
networkConfig.IPv6AcceptRA = true; networkConfig.IPv6AcceptRA = true;
dhcpV6Config.PrefixDelegationHint = "::/56"; dhcpV6Config.PrefixDelegationHint = "::/56";
}
//
# Traffic Shaping # Traffic Shaping
{
extraConfig = '' extraConfig = ''
[CAKE] [CAKE]
Parent = root Parent = root
@ -56,100 +50,36 @@ in
Bandwidth = ${toString upstream.upBandwidth}K Bandwidth = ${toString upstream.upBandwidth}K
''} ''}
''; '';
} }) upstreamInterfaces;
) upstreamInterfaces;
networking.nat = lib.optionalAttrs enabled { networking.nat = lib.optionalAttrs enabled {
enable = true; enable = true;
enableIPv6 = true;
internalInterfaces = [ "core" ]; internalInterfaces = [ "core" ];
externalInterface = firstUpstreamInterface; externalInterface = firstUpstreamInterface;
externalIP = staticIpv4Address; externalIP = upstreamInterfaces.${firstUpstreamInterface}.upstream.staticIpv4Address;
extraCommands = '' extraCommands =
# Add workaround for upstreams with wonky MTU
iptables -t mangle -A FORWARD \
-p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --clamp-mss-to-pmtu
ip6tables -t mangle -A FORWARD \
-p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --clamp-mss-to-pmtu
# Prohibit SMTP except for servers
iptables -N fwd_smtp || \
iptables -F fwd_smtp
iptables -A fwd_smtp --source ${config.site.net.serv.subnet4} -j RETURN
iptables -A fwd_smtp --dest ${config.site.net.serv.subnet4} -j RETURN
iptables -A fwd_smtp --source ${config.site.net.flpk.subnet4} -j RETURN
iptables -A fwd_smtp --dest ${config.site.net.flpk.subnet4} -j RETURN
iptables -A fwd_smtp -j REJECT
iptables -I FORWARD -p tcp --dport 25 -j fwd_smtp
ip6tables -N fwd_smtp || \
ip6tables -F fwd_smtp
${lib.concatMapStrings (subnet6: ''
ip6tables -A fwd_smtp --source ${subnet6} -j RETURN
ip6tables -A fwd_smtp --dest ${subnet6} -j RETURN
'') (builtins.concatMap builtins.attrValues [
config.site.net.serv.subnets6
config.site.net.flpk.subnets6
])}
ip6tables -A fwd_smtp -j REJECT
ip6tables -I FORWARD -p tcp --dport 25 -j fwd_smtp
${lib.optionalString (staticIpv4Address != null) ''
# Allow connections to ${staticIpv4Address} from other hosts behind NAT
${lib.concatMapStrings (fwd: let
m = builtins.match "([0-9.]+):([0-9-]+)" fwd.destination;
destinationIP = if m == null then throw "bad ip:ports `${fwd.destination}'" else lib.elemAt m 0;
destinationPorts = if m == null then throw "bad ip:ports `${fwd.destination}'" else builtins.replaceStrings ["-"] [":"] (lib.elemAt m 1);
in ''
iptables -t nat -A nixos-nat-pre \
-d ${staticIpv4Address} -p ${fwd.proto} \
--dport ${builtins.toString fwd.sourcePort} \
-j DNAT --to-destination ${fwd.destination}
iptables -t nat -A nixos-nat-post \
-d ${destinationIP} -p ${fwd.proto} \
--dport ${destinationPorts} \
-s 172.20.72.0/21 -j MASQUERADE
iptables -t nat -A nixos-nat-post \
-d ${destinationIP} -p ${fwd.proto} \
--dport ${destinationPorts} \
-s ${config.site.net.c3d2.subnet4} -j MASQUERADE
'') config.networking.nat.forwardPorts}
''}
# Do not NAT our public IPv4 addresses
${lib.concatMapStringsSep "\n" (net:
lib.concatMapStrings (subnet: ''
iptables -t nat -I nixos-nat-post \
-o ${net} \
-s ${subnet} \
-j RETURN
'') upstreamInterfaces.${net}.upstream.noNat.subnets4 or []
) (builtins.attrNames hostConf.interfaces)}
# Provide IPv6 upstream for everyone, using NAT66 when not from # Provide IPv6 upstream for everyone, using NAT66 when not from
# our static prefixes # our static prefixes
${lib.concatMapStringsSep "\n" (net: lib.concatMapStringsSep "\n" (net: ''
lib.concatMapStrings (subnet: '' ip6tables -t nat -N ${net}_nat || \
ip6tables -t nat -I nixos-nat-post \ ip6tables -t nat -F ${net}_nat
-o ${net} \ ${lib.concatMapStringsSep "\n" (subnet: ''
ip6tables -t nat -A ${net}_nat \
-s ${subnet} \ -s ${subnet} \
-j RETURN -j RETURN
'') upstreamInterfaces.${net}.upstream.noNat.subnets6 '') upstreamInterfaces.${net}.upstream.noNat.subnets6}
) (builtins.attrNames upstreamInterfaces)} ip6tables -t nat -A ${net}_nat -j MASQUERADE
# There just have been moments without a complete ruleset. Flush
# out invalid conntrack states!
${pkgs.conntrack-tools}/bin/conntrack -F
'';
extraStopCommands = ''
iptables -F FORWARD 2>/dev/null || true
ip6tables -F FORWARD 2>/dev/null || true
ip6tables -t nat -A POSTROUTING \
-o ${net} \
-j ${net}_nat
'') (builtins.attrNames upstreamInterfaces);
extraStopCommands =
lib.concatMapStringsSep "\n" (net: ''
ip6tables -t nat -F POSTROUTING 2>/dev/null || true ip6tables -t nat -F POSTROUTING 2>/dev/null || true
''; ip6tables -t nat -F ${net}_nat 2>/dev/null || true
ip6tables -t nat -X ${net}_nat 2>/dev/null || true
'') (builtins.attrNames upstreamInterfaces);
forwardPorts = map ({ destination, sourcePort, reflect, ... }@forwardedPort: forwardPorts = map ({ destination, sourcePort, reflect, ... }@forwardedPort:
removeAttrs forwardedPort ["reflect"] // { removeAttrs forwardedPort ["reflect"] // {
@ -159,7 +89,11 @@ in
else "${destination}:${toString sourcePort}"; else "${destination}:${toString sourcePort}";
loopbackIPs = loopbackIPs =
if reflect if reflect
then [ config.site.net.core.hosts4.${hostName} ] then builtins.filter (ip: ip != null) (
map (net:
upstreamInterfaces.${net}.upstream.staticIpv4Address
) (builtins.attrNames upstreamInterfaces)
)
else []; else [];
} }
) hostConf.forwardPorts; ) hostConf.forwardPorts;

View File

@ -1,4 +1,4 @@
{ hostName, config, lib, ... }: { hostName, inputs, config, lib, ... }:
let let
hostConf = config.site.hosts.${hostName}; hostConf = config.site.hosts.${hostName};
@ -26,7 +26,7 @@ in lib.mkIf (pppoeInterfaces != {}) {
enable = true; enable = true;
autostart = true; autostart = true;
config = '' config = ''
plugin pppoe.so plugin rp-pppoe.so
nic-${upstream.link} nic-${upstream.link}
ifname ${ifName} ifname ${ifName}
# Login settings. (PAP) # Login settings. (PAP)
@ -64,17 +64,14 @@ in lib.mkIf (pppoeInterfaces != {}) {
in networks // { in networks // {
"${ifName}" = { "${ifName}" = {
matchConfig.Name = "${ifName}"; matchConfig.Name = "${ifName}";
linkConfig = lib.optionalAttrs (ifName == "core") {
# interface is stuck in "routable (configuring)" and blocks systemd-networkd-wait-online
# TODO: figure out why exactly
RequiredForOnline = false;
};
networkConfig = { networkConfig = {
DHCP = lib.mkForce "ipv6"; DHCP = lib.mkOverride 900 "ipv6";
# accept config set by pppd # accept config set by pppd
KeepConfiguration = "yes"; KeepConfiguration = "yes";
}; };
dhcpV6Config = { dhcpV6Config = {
RapidCommit = true;
ForceDHCPv6PDOtherInformation = true;
PrefixDelegationHint = "::/56"; PrefixDelegationHint = "::/56";
}; };
}; };
@ -84,4 +81,11 @@ in lib.mkIf (pppoeInterfaces != {}) {
}; };
}) {} (builtins.attrNames pppoeInterfaces); }) {} (builtins.attrNames pppoeInterfaces);
# TODO: needed?
networking.nat.extraCommands = ''
iptables -A FORWARD \
-p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --clamp-mss-to-pmtu
'';
} }

View File

@ -1,58 +0,0 @@
{ config, pkgs, ... }:
let
privateKeyFile = ifName:
"/run/wireguard-keys/${ifName}.key";
ifName = "vpn";
in
{
systemd.services = {
"wireguard-key-${ifName}" = {
description = "Create key file for wireguard interface '${ifName}'";
requiredBy = [ "systemd-networkd.service" ];
before = [ "systemd-networkd.service" ];
serviceConfig.Type = "oneshot";
script = ''
#! ${pkgs.runtimeShell} -e
F=${privateKeyFile ifName}
mkdir -p -m 0700 $(dirname $F)
chown systemd-network:systemd-network $(dirname $F)
rm -f $F
cat >$F <<EOF
${config.site.vpn.wireguard.privateKey}
EOF
chmod 0400 $F
chown systemd-network:systemd-network $F
'';
};
};
systemd.network.netdevs.vpn = {
netdevConfig = {
Name = ifName;
Kind = "wireguard";
};
wireguardConfig = {
PrivateKeyFile = privateKeyFile ifName;
ListenPort = config.site.vpn.wireguard.port;
};
wireguardPeers = map ({ publicKey, allowedIPs }: {
wireguardPeerConfig = {
PublicKey = publicKey;
AllowedIPs = allowedIPs ++ [ "fe80::/64" "ff02::/16" ];
};
}) config.site.vpn.wireguard.peers;
};
systemd.network.networks.vpn.addresses = [ {
addressConfig = {
Address = "fe80::1/64";
Scope = "link";
};
} ];
environment.systemPackages = [
pkgs.wireguard-tools
];
}

View File

@ -1,7 +1,7 @@
# wireguard upstreams (like njalla and flpk, not like vpn dialup. see vpn-gw)
{ hostName, config, lib, pkgs, ... }: { hostName, config, lib, pkgs, ... }:
let let
gateway = "upstream1";
tunnels = lib.filterAttrs (_: { wireguard, ... }: tunnels = lib.filterAttrs (_: { wireguard, ... }:
wireguard != null wireguard != null
@ -16,7 +16,7 @@ let
"/run/wireguard-keys/${ifName}.key"; "/run/wireguard-keys/${ifName}.key";
wireguardMark = 3; wireguardMark = 3;
vpnTable = 100; vpn4Table = 100;
in in
{ {
systemd.services = builtins.foldl' (services: ifName: services // { systemd.services = builtins.foldl' (services: ifName: services // {
@ -52,6 +52,7 @@ in
}; };
wireguardConfig = { wireguardConfig = {
PrivateKeyFile = privateKeyFile ifName; PrivateKeyFile = privateKeyFile ifName;
# Mark for routing with another routing table
FirewallMark = wireguardMark; FirewallMark = wireguardMark;
}; };
wireguardPeers = [ { wireguardPeers = [ {
@ -67,10 +68,10 @@ in
# Wireguard transported through another routing table # Wireguard transported through another routing table
# (containing upstream by bird ospf) # (containing upstream by bird ospf)
core.routingPolicyRules = [ { core.routingPolicyRules = [ {
# Marked wireguard packets take the vpn routing table # Marked wireguard packets take the vpn4 routing table
routingPolicyRuleConfig = { routingPolicyRuleConfig = {
Table = vpn4Table;
FirewallMark = wireguardMark; FirewallMark = wireguardMark;
Table = vpnTable;
}; };
} ]; } ];
} // builtins.mapAttrs (ifName: { wireguard, upstream, ... }: { } // builtins.mapAttrs (ifName: { wireguard, upstream, ... }: {
@ -83,12 +84,12 @@ in
# IPv4 default route # IPv4 default route
networkConfig.DefaultRouteOnDevice = true; networkConfig.DefaultRouteOnDevice = true;
routes = [ {
# IPv6 default route # IPv6 default route
routes = [ {
routeConfig.Destination = "::/0"; routeConfig.Destination = "::/0";
} ]; } ];
extraConfig = lib.mkIf (upstream.upBandwidth != null) '' extraConfig = ''
[CAKE] [CAKE]
Parent = root Parent = root
# DOCSIS overhead # DOCSIS overhead
@ -109,7 +110,7 @@ in
networking.iproute2 = lib.mkIf enabled { networking.iproute2 = lib.mkIf enabled {
enable = true; enable = true;
rttablesExtraConfig = '' rttablesExtraConfig = ''
${toString vpnTable} vpn ${toString vpn4Table} vpn4
''; '';
}; };

View File

@ -0,0 +1,55 @@
{ pkgs, lib, config, hostName, ... }:
let
hostConf = config.site.hosts.${hostName};
cfg = hostConf.services.yggdrasil;
in lib.mkIf cfg.enable {
networking.firewall.enable = false;
boot.postBootCommands = ''
if [ ! -c /dev/net/tun ]; then
mkdir -p /dev/net
mknod -m 666 /dev/net/tun c 10 200
fi
'';
# Forward traffic under the prefix.
boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = 1;
networking.nat = {
enable = true;
# Provide NAT66 for everyone with addresses foreign to Yggdrasil
extraCommands = ''
ip6tables -t nat -A POSTROUTING ! --src 200::/7 -o ygg -j MASQUERADE
'';
};
systemd.tmpfiles.rules = [
"d /var/lib/yggdrasil 0700 root root -"
"L+ /var/lib/yggdrasil/keys.json - - - - ${builtins.toFile "keys.json" cfg.keys}"
];
services.yggdrasil = {
enable = true;
persistentKeys = true;
config = {
IfName = "ygg";
Peers = # https://publicpeers.neilalexander.dev/
[
# deutschland
"tcp://[2a01:4f8:172:9ce::2]:1194" # janastu
# czechia
"tcp://[2a03:3b40:fe:ab::1]:46370" # emery vpsfree.cz
# poland
"tls://[2001:41d0:601:1100::cf2]:11129"
];
NodeInfo = {
# This information is visible to the network.
name = "y.c3d2.de";
location = "Dresden";
email = "ehmry@c3d2.de";
};
};
};
}

View File

@ -1,13 +1,13 @@
# Pulls together NixOS configuration modules according to the # Pulls together NixOS configuration modules according to the
# name/role of the host to be built. # name/role of the host to be built.
{ hostName, lib, ... }: { hostName, config, lib, pkgs, ... }:
let let
inherit (lib) optionals; inherit (lib) optionals;
hostConfig = lib.config.site.hosts.${hostName}; hostConfig = lib.config.site.hosts.${hostName};
in { in {
inherit (lib.config) site; site = lib.config.site;
imports = [ imports = [
../lib/config/options.nix ../lib/config/options.nix
@ -20,27 +20,24 @@ in {
./server/default.nix ./server/default.nix
] ++ ] ++
optionals (hostConfig.role == "container") [ optionals (hostConfig.role == "container") [
./container/lxc-config.nix
./container/defaults.nix ./container/defaults.nix
./container/dhcp-server.nix ./container/dhcp-server.nix
./container/wireguard.nix ./container/wireguard.nix
./container/dns.nix ./container/dns.nix
./container/dnscache.nix ./container/dnscache.nix
./container/yggdrasil.nix
] ++ ] ++
optionals lib.config.site.hosts.${hostName}.isRouter [ optionals lib.config.site.hosts.${hostName}.isRouter [
./container/bird.nix ./container/bird.nix
] ++ ] ++
optionals ( optionals (builtins.match "upstream.*" hostName != null) [
builtins.match "upstream.*" hostName != null ||
hostName == "flpk-gw"
) [
./container/upstream.nix ./container/upstream.nix
./container/upstream/pppoe.nix ./container/upstream/pppoe.nix
] ++ ] ++
optionals (hostName == "mgmt-gw") [ optionals (hostName == "mgmt-gw") [
./container/mgmt-gw.nix ./container/mgmt-gw.nix
] ++ ] ++
optionals (hostName == "vpn-gw") [ optionals (hostName == "netboot") [
./container/vpn.nix ./container/netboot.nix
]; ];
} }

View File

@ -1,4 +1,4 @@
{ hostName, inputs, config, lib, pkgs, ... }: { hostName, inputs, pkgs, config, options, lib, ... }:
{ {
boot.kernelParams = [ boot.kernelParams = [
@ -7,9 +7,11 @@
# Prevents automatic creation of interface bond0 by the kernel # Prevents automatic creation of interface bond0 by the kernel
"bonding.max_bonds=0" "bonding.max_bonds=0"
]; ];
boot.tmp.useTmpfs = true; boot.tmpOnTmpfs = true;
# Includes wireguard # Includes wireguard
boot.kernelPackages = config.boot.zfs.package.latestCompatibleLinuxPackages; boot.kernelPackages = pkgs.linuxPackages_latest;
# Keep building
boot.zfs.enableUnstable = true;
# no persistent logs # no persistent logs
services.journald.extraConfig = '' services.journald.extraConfig = ''
@ -23,18 +25,11 @@
registry = { registry = {
nixpkgs.flake = inputs.nixpkgs; nixpkgs.flake = inputs.nixpkgs;
}; };
settings = {
substituters = lib.mkBefore [ "https://hydra.hq.c3d2.de" ];
trusted-public-keys = [
"nix-serve.hq.c3d2.de:KZRGGnwOYzys6pxgM8jlur36RmkJQ/y8y62e52fj1ps=%"
];
};
}; };
documentation = { documentation = {
enable = lib.mkForce false; enable = false;
nixos.enable = lib.mkForce false; nixos.enable = false;
}; };
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
@ -42,8 +37,6 @@
bridge-utils bridge-utils
conntrack-tools conntrack-tools
dhcpcd dhcpcd
dhcpdump
dig
ethtool ethtool
git git
iftop iftop
@ -56,7 +49,6 @@
screen screen
speedtest-cli speedtest-cli
tcpdump tcpdump
tmux
traceroute traceroute
vim vim
wget wget
@ -64,25 +56,6 @@
networking.hostName = hostName; networking.hostName = hostName;
programs = {
fzf.keybindings = true;
git = {
enable = true;
config = {
alias = {
co = "checkout";
lg = "log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold y
ow)%d%C(reset)'";
remote = "remote -v";
st = "status";
undo = "reset --soft HEAD^";
};
pull.rebase = true;
rebase.autoStash = true;
};
};
};
users.users.root.initialHashedPassword = ""; users.users.root.initialHashedPassword = "";
system.stateVersion = "20.09"; system.stateVersion = "20.09";

View File

@ -1,18 +1,11 @@
{ hostName, config, lib, ... }: { hostName, config, lib, ... }:
let lib.mkIf config.site.hosts.${hostName}.firewall.enable {
hostConfig = config.site.hosts.${hostName}; networking.firewall = {
in {
networking.firewall = lib.mkIf hostConfig.firewall.enable {
enable = true; enable = true;
extraCommands = '' extraCommands = ''
${lib.optionalString hostConfig.isRouter ''
ip46tables -I nixos-fw -p ospfigp -j ACCEPT
''}
ip46tables -A FORWARD -i core -m state --state ESTABLISHED,RELATED -j ACCEPT ip46tables -A FORWARD -i core -m state --state ESTABLISHED,RELATED -j ACCEPT
ip46tables -A FORWARD -i core -j REJECT ip46tables -A FORWARD -i core -j REJECT --reject-with net-unreach
''; '';
extraStopCommands = '' extraStopCommands = ''
ip46tables -F FORWARD ip46tables -F FORWARD

View File

@ -1,4 +1,4 @@
{ hostName, config, lib, ... }: { hostName, config, lib, pkgs, ... }:
let let
# pick an address for a net's gateway # pick an address for a net's gateway

View File

@ -1,4 +1,4 @@
{ pkgs, ... }: { pkgs, nixpkgs-master, ... }:
{ {
boot.kernelModules = [ "kvm-intel" "pppoe" ]; boot.kernelModules = [ "kvm-intel" "pppoe" ];
boot.kernelParams = [ "nomodeset" ]; boot.kernelParams = [ "nomodeset" ];
@ -8,20 +8,16 @@
time.timeZone = "Europe/Berlin"; time.timeZone = "Europe/Berlin";
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
git wget vim git screen
inetutils # telnet
ipmitool ipmitool
liboping # noping
screen
vim
wget
]; ];
services.openssh.enable = true;
services.openssh = { services.openssh.permitRootLogin = "prohibit-password";
enable = true;
settings.PermitRootLogin = "prohibit-password";
};
# additional config for bare metal # additional config for bare metal
services.collectd.plugins.ipmi = ""; services.collectd = {
plugins.ipmi = "";
# FIXME: IPMI is only available with nixpkgs-21.11 onwards
package = nixpkgs-master.legacyPackages.${pkgs.system}.collectd;
};
} }

View File

@ -1,4 +1,4 @@
{ self, config, lib, pkgs, ... }: { hostName, self, config, lib, pkgs, ... }:
let let
# Containers that are run on this host # Containers that are run on this host
@ -10,6 +10,70 @@ let
enabled = containers != {}; enabled = containers != {};
# linux iface name max length = 15
shortenNetName = name:
if builtins.match "priv(.*)" name != null
then "p" + builtins.substring 4 9 name
else name;
checkIfname = ifname: let
len = builtins.stringLength ifname;
in if len > 15
then throw "Interface name ${ifname} is ${toString (len - 15)} chars too long."
else ifname;
# `lxc.net.*` formatter for lxc.container.conf files
netConfig = ctName: interfaces:
let
config = map (netName:
let
ifData = interfaces.${netName};
in {
type = ifData.type;
name = checkIfname netName;
flags = "up";
hwaddr = if ifData ? hwaddr && ifData.hwaddr != null
then ifData.hwaddr
else "0A:14:48:xx:xx:xx";
} // (lib.optionalAttrs (ifData.type == "veth") {
veth.pair = checkIfname "${shortenNetName ctName}-${shortenNetName netName}";
veth.mode = checkIfname "bridge";
link = checkIfname netName;
}) // (lib.optionalAttrs (ifData.type == "phys") {
link = checkIfname "ext-${netName}";
})
) (builtins.attrNames interfaces);
attrNamesOrdered = attrs:
if attrs ? type
then [ "type" ] ++ lib.remove "type" (builtins.attrNames attrs)
else builtins.attrNames attrs;
serialize = name: x:
if builtins.isString x
then "${name} = ${x}\n"
else if builtins.isAttrs x
then builtins.concatStringsSep "" (
map (n: serialize "${name}.${n}" x.${n}) (attrNamesOrdered x)
)
else if builtins.isList x
then
let
enumerate = xs: n:
if xs == []
then []
else [ {
e = builtins.head xs;
i = n;
} ] ++ enumerate (builtins.tail xs) (n + 1);
in
builtins.concatStringsSep "" (
map ({ e, i }: serialize "${name}.${toString i}" e) (enumerate x 0)
)
else throw "Invalid data in lxc net config for ${name}: ${lib.generators.toPretty {} x}";
in
serialize "lxc.net" config;
# User-facing script to build/update container NixOS systems # User-facing script to build/update container NixOS systems
build-script = pkgs.writeScriptBin "build-container" '' build-script = pkgs.writeScriptBin "build-container" ''
#! ${pkgs.runtimeShell} -e #! ${pkgs.runtimeShell} -e
@ -30,7 +94,6 @@ let
${ctName}) ${ctName})
echo Using prebuilt system for container $c echo Using prebuilt system for container $c
SYSTEM=${self.packages.x86_64-linux."${ctName}-rootfs"} SYSTEM=${self.packages.x86_64-linux."${ctName}-rootfs"}
CONFIG=${self.packages.x86_64-linux."${ctName}-lxc-config"}
;; ;;
'') ( '') (
builtins.attrNames ( builtins.attrNames (
@ -42,8 +105,6 @@ let
echo Building $c echo Building $c
nix build -o /nix/var/nix/gcroots/lxc/$c zentralwerk-network#$c-rootfs nix build -o /nix/var/nix/gcroots/lxc/$c zentralwerk-network#$c-rootfs
SYSTEM=$(readlink /nix/var/nix/gcroots/lxc/$c) SYSTEM=$(readlink /nix/var/nix/gcroots/lxc/$c)
nix build -o /nix/var/nix/gcroots/lxc/$c.config zentralwerk-network#$c-lxc-config
CONFIG=$(readlink /nix/var/nix/gcroots/lxc/$c.config)
;; ;;
esac esac
@ -56,7 +117,6 @@ let
mkdir -p /var/lib/lxc/$c/rootfs/$d mkdir -p /var/lib/lxc/$c/rootfs/$d
done done
ln -fs $SYSTEM/init /var/lib/lxc/$c/rootfs/init ln -fs $SYSTEM/init /var/lib/lxc/$c/rootfs/init
ln -fs $CONFIG /var/lib/lxc/$c/config
done done
# Activate all the desired container after all of them are # Activate all the desired container after all of them are
@ -102,8 +162,10 @@ in
virtualisation.lxc = lib.mkIf enabled { virtualisation.lxc = lib.mkIf enabled {
enable = true; enable = true;
# Container configs live in /etc so that they can be created
# through `environment.etc`.
systemConfig = '' systemConfig = ''
lxc.lxcpath = /var/lib/lxc lxc.lxcpath = /etc/lxc/containers
''; '';
}; };
@ -114,7 +176,50 @@ in
enable-script disable-script enable-script disable-script
]; ];
environment.etc."lxc/common.conf".source = "${pkgs.lxc}/share/lxc/config/common.conf"; # Create lxc.container.conf files
environment.etc =
builtins.foldl' (etc: ctName: etc // {
"lxc/containers/${ctName}/config" = {
enable = true;
source =
builtins.toFile "${ctName}.conf" ''
# For lxcfs and sane defaults
lxc.include = /etc/lxc/common.conf
lxc.uts.name = ${ctName}
# Handled by lxc@.service
lxc.start.auto = 0
lxc.rootfs.path = /var/lib/lxc/${ctName}/rootfs
lxc.init.cmd = "/init"
lxc.mount.entry = /nix/store nix/store none bind,ro 0 0
lxc.mount.entry = none tmp tmpfs defaults 0 0
lxc,mount.auto = proc:mixed sys:ro cgroup:mixed
lxc.autodev = 1
lxc.tty.max = 0
lxc.pty.max = 8
lxc.cap.drop = sys_module sys_time sys_nice sys_pacct sys_rawio
security.privileged = false
lxc.apparmor.profile = lxc-container-default-with-mounting
lxc.cgroup.memory.limit_in_bytes = 1G
lxc.cgroup.memory.kmem.tcp.limit_in_bytes = 128M
# tuntap
lxc.cgroup.devices.allow = c 10:200 rw
lxc.cgroup2.devices.allow = c 10:200 rw
# ppp
lxc.cgroup.devices.allow = c 108:0 rwm
lxc.cgroup2.devices.allow = c 108:0 rwm
${netConfig ctName containers.${ctName}.physicalInterfaces}
'';
};
}) {
"lxc/common.conf".source = "${pkgs.lxc}/share/lxc/config/common.conf";
} (builtins.attrNames containers);
# Systemd service template for LXC containers # Systemd service template for LXC containers
systemd.services."lxc@" = { systemd.services."lxc@" = {
@ -143,8 +248,6 @@ in
Restart = "always"; Restart = "always";
RestartSec = "1s"; RestartSec = "1s";
}; };
# Prevent restart on host nixos-rebuild switch
restartIfChanged = false;
}; };
# Starts all the containers after boot # Starts all the containers after boot

View File

@ -1,5 +1,5 @@
# Server network configuration # Server network configuration
{ config, lib, ... }: { hostName, self, config, lib, pkgs, ... }:
let let
# LXC containers on this host # LXC containers on this host
@ -114,7 +114,5 @@ in
networkConfig.Bridge = net; networkConfig.Bridge = net;
}; };
}) {} ctNets; }) {} ctNets;
wait-online.anyInterface = true;
}; };
} }

View File

@ -1,17 +1,21 @@
{ config, ... }: { config, pkgs, ... }:
{ {
# Use the systemd-boot EFI boot loader. boot.loader.grub.enable = true;
boot.loader.systemd-boot.enable = true; boot.loader.grub.version = 2;
boot.loader.efi.canTouchEfiVariables = true; boot.loader.grub.devices = [
"/dev/disk/by-path/pci-0000:05:00.0-scsi-0:1:0:0"
"/dev/disk/by-path/pci-0000:05:00.0-scsi-0:1:0:1"
];
networking.hostName = "server1"; # Define your hostname. networking.hostName = "server1"; # Define your hostname.
networking.hostId = "01010101"; networking.hostId = "12345678";
boot.initrd.availableKernelModules = [ "uhci_hcd" "ehci_pci" "ata_piix" "hpsa" "usb_storage" "usbhid" "sd_mod" "sr_mod" ]; boot.initrd.availableKernelModules = [ "uhci_hcd" "ehci_pci" "ata_piix" "hpsa" "usb_storage" "usbhid" "sd_mod" "sr_mod" ];
boot.initrd.kernelModules = [ ]; boot.initrd.kernelModules = [ ];
boot.extraModulePackages = [ ]; boot.extraModulePackages = [ ];
nixpkgs.config.allowBroken = true; nixpkgs.config.allowBroken = true;
boot.zfs.enableUnstable = true;
boot.supportedFilesystems = [ "zfs" ]; boot.supportedFilesystems = [ "zfs" ];
boot.initrd.supportedFilesystems = [ "zfs" ]; boot.initrd.supportedFilesystems = [ "zfs" ];
# Required for Broadcom NICs # Required for Broadcom NICs
@ -43,8 +47,8 @@
}; };
fileSystems."/boot" = fileSystems."/boot" =
{ device = "/dev/disk/by-label/ESP"; { device = "/dev/disk/by-uuid/23f17e88-ab7e-4dcc-a119-2ed1b9c2c91d";
fsType = "vfat"; fsType = "ext2";
}; };
swapDevices = [ ]; swapDevices = [ ];

View File

@ -1,9 +1,10 @@
{ ... }: { pkgs, ... }:
{ {
boot.initrd.availableKernelModules = [ "uhci_hcd" "ehci_pci" "ahci" "usbhid" "sd_mod" "sr_mod" ]; boot.initrd.availableKernelModules = [ "uhci_hcd" "ehci_pci" "ahci" "usbhid" "sd_mod" "sr_mod" ];
boot.initrd.kernelModules = [ ]; boot.initrd.kernelModules = [ ];
nixpkgs.config.allowBroken = true; nixpkgs.config.allowBroken = true;
boot.zfs.enableUnstable = true;
boot.supportedFilesystems = [ "zfs" ]; boot.supportedFilesystems = [ "zfs" ];
boot.initrd.supportedFilesystems = [ "zfs" ]; boot.initrd.supportedFilesystems = [ "zfs" ];
boot.extraModulePackages = [ ]; boot.extraModulePackages = [ ];
@ -38,6 +39,7 @@
}; };
boot.loader.grub.enable = true; boot.loader.grub.enable = true;
boot.loader.grub.version = 2;
boot.loader.grub.device = "/dev/sda"; boot.loader.grub.device = "/dev/sda";
networking.hostName = "server2"; # Define your hostname. networking.hostName = "server2"; # Define your hostname.

319
nix/pkgs/ap.nix Normal file
View File

@ -0,0 +1,319 @@
{ self, pkgs, hostName, config, hostConfig, ... }:
with pkgs;
with lib;
let
ports = self.lib.getOpenwrtPorts hostConfig.model;
uciDeleteAll = key: ''
while uci -q delete ${key}[-1]; do :; done
'';
# hostBridgedNets =
# self.lib.unique (
# builtins.concatMap ({ ssids, ... }:
# map ({ net, ... }:
# net
# ) (builtins.attrValues ssids)
# ) (builtins.attrValues hostConfig.wifi)
# );
openwrtModel = self.lib.getOpenwrtModel hostConfig.model;
hasSwitch =
any ({ switch ? null, ... }: switch != null)
(builtins.attrValues openwrtModel.ports);
portsDoc =
let
portByIndex = builtins.foldl' (result: port:
let
key = if port ? index
then port.index
else if port ? interface
then port.interface
else "How to identify port ${lib.generators.toPretty {} port}?";
in result // {
"${key}" = port;
}
) {} (builtins.attrValues openwrtModel.ports);
in
concatMapStringsSep ", " (index:
"${index}:${
if portByIndex.${index} ? port
then portByIndex.${index}.port
else if portByIndex.${index} ? interface
then portByIndex.${index}.interface
else throw "What is port ${lib.generators.toPretty {} portByIndex.${index}.port}?"
}"
) (
builtins.sort builtins.lessThan (
builtins.attrNames portByIndex
)
);
switchHostInterface =
let
hostPorts = sort builtins.lessThan (
map ({ interface, ... }: interface) (
builtins.attrValues (
filterAttrs (_: { type, ... }: type == "host")
openwrtModel.ports
)
)
);
in if hostPorts == []
then throw "No host ports found for OpenWRT model ${hostConfig.model}"
else builtins.head hostPorts;
switchPortIndices = f:
map ({ index, ... }: index) (
builtins.attrValues (
filterAttrs (_: port: port ? index && f port)
openwrtModel.ports
)
);
trunked = map (index: "${index}t");
# OpenWRT switch ports string ("0t 1t 2 3 4") for a network (VLAN)
switchPortsConfig = net:
concatStringsSep " " (
# Host interface
trunked (switchPortIndices ({ interface ? null, ... }: interface == switchHostInterface))
++
# Access networks
optionals (hostConfig.links ? ${net}) (
builtins.concatMap (port':
switchPortIndices ({ port ? null, ... }: port == port')
) hostConfig.links.${net}.ports
)
++
# Trunk ports
builtins.concatMap (port':
trunked (switchPortIndices ({ port ? null, ... }: port == port'))
) (
builtins.concatMap ({ ports, ... }: ports) (
builtins.attrValues (
filterAttrs (_: { trunk, ... }:
trunk
) hostConfig.links
))
)
);
networkInterfaces = net:
let
inherit (config.site.net.${net}) vlan;
ifaces =
unique (
builtins.concatMap ({ trunk, ports, switch ? null, ... }:
builtins.concatMap (port:
builtins.concatMap (portData:
if portData ? port && port == portData.port
then [ ((
if portData ? switch
then switchHostInterface
else if portData ? interface
then portData.interface
else throw "Cannot find interface for ${port} on OpenWRT model ${hostConfig.model}"
) + (
if trunk || switch != null
then ".${toString vlan}"
else ""
)) ]
else []
) (builtins.attrValues openwrtModel.ports)
) ports
) (
builtins.attrValues (
filterAttrs (link: { nets, ... }:
link == net || builtins.elem net nets
) hostConfig.links
)
)
);
in
if ifaces == []
then throw "No interfaces found for ${net} on ${hostName}"
else ifaces;
in ''
#! ${pkgs.runtimeShell} -e
${if hostConfig.firstboot
then ''
ssh-keygen -R 192.168.1.1
ssh root@192.168.1.1 \
"ash -e -x" <<__SSH__
'' else ''
ssh root@${config.site.net.mgmt.hosts4.${hostName}} \
"ash -e -x" <<__SSH__
''}
# Set root password
echo -e '${hostConfig.password}\n${hostConfig.password}' | passwd
# add ssh pubkeys
${concatMapStrings (sshPubKey: ''
echo "${sshPubKey}" > /etc/dropbear/authorized_keys
'') config.site.sshPubKeys}
# System configuration
${uciDeleteAll "network.@switch_vlan"}
${uciDeleteAll "wireless.@wifi"}
uci set system.@system[0].hostname=${hostName}
uci set dhcp.@dnsmasq[0].enabled=0
uci set system.@system[0].log_ip=${config.site.net.mgmt.hosts4.logging}
uci set system.@system[0].log_proto=udp
# Switch config
${optionalString hasSwitch ''
# Ports ${portsDoc}
${concatMapStrings (net: ''
uci add network switch_vlan
uci set network.@switch_vlan[-1]=switch_vlan
uci set network.@switch_vlan[-1].device='switch0'
uci set network.@switch_vlan[-1].vlan='${toString config.site.net.${net}.vlan}'
uci set network.@switch_vlan[-1].ports='${switchPortsConfig net}'
uci set network.@switch_vlan[-1].comment='${net}'
'') (
sort (net1: net2:
config.site.net.${net1}.vlan < config.site.net.${net2}.vlan
) (
unique (
builtins.concatMap ({ nets, ... }: nets)
(builtins.attrValues hostConfig.links)
)
)
)}
''}
# mgmt network
uci set network.mgmt=interface
uci set network.mgmt.ifname=${if builtins.length (networkInterfaces "mgmt") == 1 then builtins.head (networkInterfaces "mgmt") else throw "No interface for mgmt"}
uci set network.mgmt.proto=static
uci set network.mgmt.ipaddr=${config.site.net.mgmt.hosts4.${hostName}}
uci set network.mgmt.netmask=${self.lib.netmasks.${elemAt (
builtins.split "/" config.site.net.mgmt.subnet4
) 2}}
uci set network.mgmt.gateway=${config.site.net.mgmt.hosts4.mgmt-gw}
uci set network.mgmt.ip6addr=${config.site.net.mgmt.hosts6.dn42.${hostName}}/64
uci set network.mgmt.ip6gw=${config.site.net.mgmt.hosts6.dn42.mgmt-gw}
uci -q delete network.mgmt.dns || true
uci add_list network.mgmt.dns=${config.site.net.serv.hosts4.dnscache}
uci add_list network.mgmt.dns=${config.site.net.serv.hosts6.dn42.dnscache}
uci -q delete network.globals.ula_prefix || true
# delete unused networks
${concatMapStrings (net:
lib.optionalString (! hostConfig.interfaces ? ${net}) ''
uci -q delete network.${net} || true
''
) ([ "lan" "wan" "wan6" ] ++ builtins.attrNames config.site.net)}
# bridged networks
${concatMapStrings (net:
let
iface = hostConfig.interfaces.${net};
in optionalString (net != "mgmt" && iface.type == "bridge") ''
uci set network.${net}=interface
uci set network.${net}.type=bridge
uci set network.${net}.proto=static
uci set network.${net}.ifname='${concatStringsSep " " (networkInterfaces net)}'
'') (builtins.attrNames hostConfig.interfaces)
}
uci -q delete wireless.default_radio0 || true
uci -q delete wireless.default_radio1 || true
${concatStrings (imap0 (index: path:
let
radioConfig = hostConfig.wifi.${path};
ifPrefix = if radioConfig.channel < 15
then "wlan2"
else "wlan5";
in ''
uci set wireless.radio${toString index}=wifi-device
uci set wireless.radio${toString index}.type=mac80211
uci set wireless.radio${toString index}.country=DE
uci set wireless.radio${toString index}.channel=${toString radioConfig.channel}
uci set wireless.radio${toString index}.path=${path}
uci set wireless.radio${toString index}.htmode=${radioConfig.htmode}
uci set wireless.radio${toString index}.noscan=1
uci -q delete wireless.radio${toString index}.disabled || true
${concatMapStrings (ssid:
let
ssidConfig = radioConfig.ssids.${ssid};
in ''
uci add wireless wifi-iface
uci set wireless.@wifi-iface[-1].ifname=${ifPrefix}-${ssidConfig.net}
uci set wireless.@wifi-iface[-1].device=radio${toString index}
uci set wireless.@wifi-iface[-1].ssid='${ssid}'
uci set wireless.@wifi-iface[-1].mode=ap
uci set wireless.@wifi-iface[-1].network=${ssidConfig.net}
uci set wireless.@wifi-iface[-1].mcast_rate=18000
${if (ssidConfig.psk != null)
then ''
uci set wireless.@wifi-iface[-1].encryption=psk2
uci set wireless.@wifi-iface[-1].key='${ssidConfig.psk}'
''
else ''
uci set wireless.@wifi-iface[-1].encryption=none
uci -q delete wireless.@wifi-iface[-1].key || true
''}
''
) (builtins.attrNames radioConfig.ssids)}
'') (builtins.attrNames hostConfig.wifi))}
uci commit
# Cronjob that makes sure WiFi is only visible when server with all
# the gateways is reachable
cat >/etc/crontabs/root <<__CRON__
* * * * * /usr/sbin/wifi-on-link.sh
__CRON__
cat >/usr/sbin/wifi-on-link.sh <<__SH__
#!/bin/sh
if (ping -c 1 -W 3 ${config.site.net.mgmt.hosts4.mgmt-gw}) ; then
REACHABLE=y
else
REACHABLE=n
fi
if [ "\\\$(cat /sys/class/net/wlan2-pub/operstate)" == "up" ] ; then
UP=y
else
UP=n
fi
if [ -e /sys/class/leds/blue:dome ] ; then
ERROR_LED=/sys/class/leds/blue:dome/brightness
[ \\\$REACHABLE = y ] && echo 0 > \\\$ERROR_LED
[ \\\$REACHABLE = n ] && echo 1 > \\\$ERROR_LED
fi
[ \\\$REACHABLE = y ] && [ \\\$UP = n ] && wifi up
[ \\\$REACHABLE = n ] && [ \\\$UP = y ] && wifi down
exit 0
__SH__
chmod a+rx /usr/sbin/wifi-on-link.sh
/etc/init.d/cron restart
for svc in dnsmasq uhttpd ; do
rm -f /etc/rc.d/*\$svc
/etc/init.d/\$svc stop || true
done
${lib.optionalString hostConfig.firstboot "reboot"}
__SSH__
echo "Base configuration done \\o/"
echo "Later run: ap_install_collectd.sh ${config.site.net.mgmt.hosts4.${hostName}}"
''

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash #!/bin/bash
for HOST in $@ ; do for HOST in $@ ; do
ssh root@$HOST \ ssh root@$HOST \

View File

@ -1,20 +1,16 @@
{ self, nixpkgs, system, openwrt-imagebuilder }: { self, nixpkgs, system }:
let let
inherit (self.lib) config; inherit (self.lib) config;
pkgs = nixpkgs.legacyPackages.${system}; pkgs = nixpkgs.legacyPackages.${system};
inherit (pkgs) lib;
export-openwrt-models = pkgs.writeText "openwrt-models.nix" ( export-openwrt-models = pkgs.writeText "openwrt-models.nix" (
lib.generators.toPretty {} self.lib.openwrtModels nixpkgs.lib.generators.toPretty {} self.lib.openwrtModels
); );
export-config = pkgs.writeText "config.nix" ( export-config = pkgs.writeText "config.nix" (
lib.generators.toPretty {} ( nixpkgs.lib.generators.toPretty {} config
lib.recursiveUpdate );
config
{ site.dns.localZones = self.lib.dns.localZones; }
));
encrypt-secrets = pkgs.writeScriptBin "encrypt-secrets" '' encrypt-secrets = pkgs.writeScriptBin "encrypt-secrets" ''
#! ${pkgs.runtimeShell} -e #! ${pkgs.runtimeShell} -e
@ -45,7 +41,7 @@ let
''; '';
network-cypher-graphs = import ./network-cypher-graphs.nix { inherit config pkgs; }; network-cypher-graphs = import ./network-cypher-graphs.nix { inherit config pkgs; };
network-graphs = import ./network-graphs.nix { inherit config lib pkgs; }; network-graphs = import ./network-graphs.nix { inherit config pkgs; };
mkRootfs = hostName: mkRootfs = hostName:
self.nixosConfigurations.${hostName}.config.system.build.toplevel; self.nixosConfigurations.${hostName}.config.system.build.toplevel;
@ -55,20 +51,7 @@ let
"${hostName}-rootfs" = mkRootfs hostName; "${hostName}-rootfs" = mkRootfs hostName;
}) {} ( }) {} (
builtins.attrNames ( builtins.attrNames (
lib.filterAttrs (_: { role, ... }: builtins.elem role ["server" "container"]) nixpkgs.lib.filterAttrs (_: { role, ... }: builtins.elem role ["server" "container"])
config.site.hosts
)
);
mkLxcConfig = hostName:
self.nixosConfigurations.${hostName}.config.system.build.lxcConfig;
lxc-configs =
builtins.foldl' (rootfs: hostName: rootfs // {
"${hostName}-lxc-config" = mkLxcConfig hostName;
}) {} (
builtins.attrNames (
lib.filterAttrs (_: { role, ... }: role == "container")
config.site.hosts config.site.hosts
) )
); );
@ -76,33 +59,26 @@ let
vm-packages = vm-packages =
builtins.foldl' (rootfs: hostName: rootfs // { builtins.foldl' (rootfs: hostName: rootfs // {
"${hostName}-vm" = self.nixosConfigurations.${hostName}.config.system.build.vm "${hostName}-vm" = self.nixosConfigurations.${hostName}.config.system.build.vm
.overrideAttrs (_oa: { .overrideAttrs (oa: {
meta.mainProgram = "run-${hostName}-vm"; meta.mainProgram = "run-${hostName}-vm";
}); });
}) {} ( }) {} (
builtins.attrNames ( builtins.attrNames (
lib.filterAttrs (_: { role, ... }: role == "server") nixpkgs.lib.filterAttrs (_: { role, ... }: role == "server")
config.site.hosts config.site.hosts
) )
); );
openwrt = import ./openwrt { inherit self nixpkgs system openwrt-imagebuilder; }; all-rootfs = with pkgs;
runCommand "all-rootfs" {} ''
openwrt-packages = builtins.foldl' (images: hostName: images // { mkdir -p $out
${hostName} = pkgs.writeScriptBin "${hostName}.sh" ( ${lib.concatMapStrings (pkg: ''
openwrt.sshScript hostName ln -s ${pkg} $out/${pkg.name}
); '') (builtins.attrValues rootfs-packages)}
"${hostName}-image" = openwrt.buildImage hostName; '';
}) {} (
builtins.attrNames (
lib.filterAttrs (_: { role, ... }:
role == "ap"
) config.site.hosts
)
);
device-templates = import ./device-templates.nix { device-templates = import ./device-templates.nix {
inherit self nixpkgs system openwrt; inherit self nixpkgs system;
}; };
dns-slaves = import ./dns-slaves.nix { dns-slaves = import ./dns-slaves.nix {
@ -116,26 +92,9 @@ let
subnetplans = import ./subnetplans.nix { subnetplans = import ./subnetplans.nix {
inherit self nixpkgs system; inherit self nixpkgs system;
}; };
gateway-report = import ./gateway-report.nix {
inherit self nixpkgs system;
};
switch-report = import ./switch-report.nix {
inherit self nixpkgs system;
};
vlan-report = import ./vlan-report.nix {
inherit self nixpkgs system;
};
homepage = pkgs.callPackage ./homepage {
inherit self;
};
in in
rootfs-packages // lxc-configs // vm-packages // device-templates // openwrt-packages // network-graphs // network-cypher-graphs // starlink // subnetplans // { rootfs-packages // vm-packages // device-templates // network-graphs // network-cypher-graphs // starlink // subnetplans // {
inherit export-openwrt-models export-config dns-slaves inherit all-rootfs export-openwrt-models export-config dns-slaves
encrypt-secrets decrypt-secrets switch-to-production encrypt-secrets decrypt-secrets switch-to-production
homepage gateway-report switch-report vlan-report
; ;
} }

View File

@ -1,4 +1,4 @@
{ self, nixpkgs, system, openwrt }: { self, nixpkgs, system }:
with nixpkgs.lib; with nixpkgs.lib;
let let
pkgs = nixpkgs.legacyPackages.${system}; pkgs = nixpkgs.legacyPackages.${system};
@ -11,13 +11,17 @@ let
args = { args = {
inherit self hostName config hostConfig pkgs; inherit self hostName config hostConfig pkgs;
}; };
in import (./switches + "/${model}.nix") ( in {
args // import ./switches/shared.nix args ap = import ./ap.nix args;
) switch = import (./switches + "/${model}.nix")
(args //
import ./switches/shared.nix args
);
}.${role}
) )
) ( ) (
filterAttrs (_: { role, model, ... }: filterAttrs (_: { role, ... }:
role == "switch" && model != "dumb" role == "ap" || role == "switch"
) config.site.hosts ) config.site.hosts
); );

View File

@ -15,13 +15,13 @@ let
in in
writeText "named.slave.conf" ( writeText "named.slave.conf" (
lib.concatMapStringsSep "\n" ({ name, ... }: '' lib.concatMapStringsSep "\n" ({ name, ns, ... }: ''
zone "${name}" IN { zone "${name}" IN {
type slave; type slave;
masters {${mastersStr} }; masters {${mastersStr} };
file "/var/lib/bind/slave/${name}.zone"; file "/var/lib/bind/slave/${name}.zone";
allow-notify {${mastersStr} }; allow-notify {${mastersStr} };
allow-query { any; }; allow-query { all; };
}; };
'') ( '') (
# public zones only # public zones only

View File

@ -1,120 +0,0 @@
{ self, nixpkgs, system }:
with nixpkgs.legacyPackages.${system};
let
config = self.lib.config;
in
writeText "gateway-report.md" ''
# Gateway Report
${lib.concatMapStrings (net:
let
netConfig = config.site.net.${net};
routers4 = builtins.filter (hostName:
config.site.hosts ? ${hostName} &&
config.site.hosts.${hostName}.isRouter
) (
builtins.attrNames netConfig.hosts4
);
routers6 = builtins.filter (hostName:
config.site.hosts ? ${hostName} &&
config.site.hosts.${hostName}.isRouter
) (lib.unique (
builtins.concatMap builtins.attrNames (builtins.attrValues netConfig.hosts6)
));
upstreamAt = l: n:
if n < builtins.length l
then
let
hostName = builtins.elemAt l n;
hostConfig = config.site.hosts.${hostName};
providers =
map ({ upstream, ... }: upstream.provider) (
builtins.filter ({ upstream, ... }:
upstream.provider or null != null
) (builtins.attrValues hostConfig.interfaces)
);
in
"${hostName}${
lib.optionalString (providers != []) " (${lib.concatStringsSep ", " providers})"
}"
else "";
in
lib.optionalString (net != "core" && (routers4 != [] || routers6 != [])) ''
## Network ${net}
${lib.optionalString (routers4 != []) ''
### IPv4 `${netConfig.subnet4}`
| Address | Name | Primary Uplink | Fallback Uplink |
|-|-|-|-|
${lib.concatMapStrings (hostName:
let
hostConfig = config.site.hosts.${hostName};
isDhcpDefault = hostName == netConfig.dhcp.router or null;
emphasize = s:
if isDhcpDefault
then "**${s}**"
else s;
upstream4a = upstreamAt hostConfig.ospf.allowedUpstreams 0;
upstream4b = upstreamAt hostConfig.ospf.allowedUpstreams 1;
in ''
|${
emphasize netConfig.hosts4.${hostName}
}|${
emphasize hostName
}|${
upstream4a
}|${
upstream4b
}|
''
) (lib.naturalSort routers4)}
''}
${lib.optionalString (routers6 != {}) ''
### IPv6 ${lib.concatStringsSep " " (
map (s: "`${s}`") (
builtins.attrValues netConfig.subnets6
)
)}
| Address | Name | Primary Uplink | Fallback Uplink |
|-|-|-|-|
${lib.concatMapStrings (hostName:
let
hostConfig = config.site.hosts.${hostName};
isIpv6Router = hostName == netConfig.ipv6Router;
emphasize = s:
if isIpv6Router
then "**${s}**"
else s;
upstream6a = upstreamAt hostConfig.ospf.allowedUpstreams6 0;
upstream6b = upstreamAt hostConfig.ospf.allowedUpstreams6 1;
in ''
|${
emphasize (
lib.concatMapStringsSep " " (ctx:
"`${netConfig.hosts6.${ctx}.${hostName}}`"
) (builtins.filter (ctx:
netConfig.hosts6.${ctx} ? ${hostName}
) (builtins.attrNames netConfig.hosts6))
)
}|${
emphasize hostName
}|${
upstream6a
}|${
upstream6b
}|
''
) (lib.naturalSort routers6)}
''}
''
) (lib.naturalSort (builtins.attrNames config.site.net))}
''

View File

@ -1,5 +0,0 @@
{
"captive": false,
"user-portal-url": "https://zentralwerk.org/",
"venue-info-url": "https://zentralwerk.org/"
}

View File

@ -1,75 +0,0 @@
{ self
, system
, substituteAll
, stdenv
, pandoc
, bat
, ansi2html
}:
let
inherit (self.packages.${system})
export-config
gateway-report network-graphs
subnetplans switch-report vlan-report;
in
stdenv.mkDerivation {
pname = "zentralwerk-network-homepage";
version = self.lastModifiedDate;
src = ./src;
nativeBuildInputs = [
pandoc
bat
ansi2html
];
buildPhase = ''
pandoc -t html ${../../../doc/hello.md} > index.html
cat ${./linked-data.html} >> index.html
pandoc -t html ${../../../doc/vpn.md} > vpn.html
pandoc -t html ${gateway-report} > gateway-report.html
cat ${../../../cabling.md} ${switch-report} >> switch-report.md
pandoc -t html switch-report.md > switch-report.html
pandoc -t html ${vlan-report} > vlan-report.html
echo '<pre>' > config.html
bat --color=always --theme=GitHub -p ${export-config} | \
ansi2html -il >> config.html
echo '</pre>' >> config.html
ln -s ${substituteAll {
src = ./figure.html;
img = "physical.png";
caption = "Physikalische Netzwerkstruktur";
}} physical.html
ln -s ${substituteAll {
src = ./figure.html;
img = "logical.png";
caption = "Logische Netzwerkstruktur";
}} logical.html
ln -s ${subnetplans}/share/doc/zentralwerk/* .
for F in *.html; do
cat ${./header.html} "$F" ${./footer.html} > "$F.new"
rm "$F"
mv "$F.new" "$F"
done
'';
installPhase = ''
DIR=$out/share/doc/zentralwerk/www
mkdir -p $DIR
ln -s ${network-graphs}/share/doc/zentralwerk/* $DIR/
ln -s ${../../../doc/core.png} $DIR/core.png
ln -s ${./security.txt} $DIR/security.txt
ln -s ${./captive.json} $DIR/captive.json
cp *.{html,css,png,svg} $DIR/
mkdir -p $out/nix-support
echo doc homepage $DIR index.html >> $out/nix-support/hydra-build-products
'';
}

View File

@ -1,4 +0,0 @@
<figure>
<img src="@img@" alt="@caption@">
<figcaption>@caption@</figcaption>
</figure>

View File

@ -1,14 +0,0 @@
</main>
<footer>
<p>
<a href="https://gitea.c3d2.de/zentralwerk/network">git</a>
vom
<a href="https://www.c3d2.de/">C3D2</a>
im
<a href="https://www.zentralwerk.de/">Zentralwerk</a>
</p>
</footer>
</body>
</html>

View File

@ -1,35 +0,0 @@
<!DOCTYPE html>
<html lang="de" xml:lang="de">
<head>
<title>zentralwerk.org</title>
<meta charset="utf-8"/>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<meta name="robots" content="index,follow"/>
<meta name="description" content="zentralwerk-network"/>
<meta name="keywords" content="c3d2 ccc zentralwerk network"/>
<meta name="generator" content="zentralwerk-network"/>
<meta name="language" content="de"/>
<meta name="author" content="Astro"/>
<link rel="icon" type="image/png" href="zw.png"/>
<link rel="stylesheet" title="Default" type="text/css" href="style.css"/>
</head>
<body>
<header>
<h1>zentralwerk-network</h1>
<nav>
<ul>
<li><a href=".">Willkommen</a></li>
<li><a href="gateway-report.html">Router</a></li>
<li><a href="subnetplan4.html">IPv4</a></li>
<li><a href="subnetplan6.html">IPv6</a></li>
<li><a href="vlan-report.html">VLAN</a></li>
<li><a href="logical.html">Logisch</a></li>
<li><a href="physical.html">Physisch</a></li>
<li><a href="switch-report.html">Ports</a></li>
<li><a href="vpn.html">VPN</a></li>
<li><a href="config.html">Config</a></li>
</ul>
</nav>
</header>
<main>

View File

@ -1,30 +0,0 @@
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Project",
"name": "zentralwerk-network",
"image": "https://www.zentralwerk.org/zw.png",
"logo": "https://www.zentralwerk.org/zw.png",
"@id": "https://www.zentralwerk.org/",
"url": "https://www.zentralwerk.org/",
"sameAs": "https://gitea.c3d2.de/zentralwerk/network",
"address": {
"@type": "PostalAddress",
"streetAddress": "Riesaer Str. 32",
"addressLocality": "Dresden",
"postalCode": "01127",
"addressCountry": "DE"
},
"geo": {
"@type": "GeoCoordinates",
"latitude": 51.0811716,
"longitude": 13.7285633
},
"parentOrganization": {
"@type": "NGO",
"name": "Chaos Computer Club Dresden",
"@id": "https://www.c3d2.de/whois.html",
"url": "https://www.c3d2.de/whois.html"
}
}
</script>

View File

@ -1,3 +0,0 @@
Contact: mailto:astro@spaceboyz.net
Preferred-Languages: en, de
Hiring: https://www.c3d2.de/space.html

View File

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="1920"
height="1080"
viewBox="0 0 507.99999 285.75"
version="1.1"
id="svg5"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
sodipodi:docname="background.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#af1f00"
bordercolor="#cccccc"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="1"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="0.23657384"
inkscape:cx="1470.9995"
inkscape:cy="762.97531"
inkscape:window-width="1916"
inkscape:window-height="1057"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs2" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
sodipodi:type="star"
style="opacity:0.349515;fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#ffff00;stroke-width:1.21295;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
id="path163"
inkscape:flatsided="false"
sodipodi:sides="48"
sodipodi:cx="266.05429"
sodipodi:cy="144.57217"
sodipodi:r1="179.29391"
sodipodi:r2="44.823479"
sodipodi:arg1="0.36233915"
sodipodi:arg2="0.427789"
inkscape:rounded="-2.4286129e-17"
inkscape:randomized="0"
d="m 433.7067,208.12514 -126.86819,-44.95749 117.13857,66.29681 -119.91468,-61.13249 107.48296,81.01929 -110.9094,-76.26151 95.98829,94.3555 -100.00643,-90.08565 82.85123,106.07726 -87.39232,-102.36842 68.29656,115.98401 -73.28291,-112.89964 52.57333,123.90625 -57.9196,-121.4991 35.95054,129.7084 -41.56528,-128.01968 18.71264,133.29122 -24.49976,-132.34982 1.15456,134.59339 -7.01505,-134.41541 -16.42328,133.59262 10.5897,-134.18111 -33.72012,130.30605 28.01326,-131.65094 -50.43999,124.7899 44.95749,-126.86818 -66.29682,117.13856 61.1325,-119.91468 -81.01929,107.48296 76.2615,-110.9094 -94.3555,95.98829 90.08566,-100.00643 -106.07726,82.85123 102.36842,-87.39232 -115.98401,68.29657 112.89963,-73.28291 -123.90624,52.57332 121.4991,-57.9196 L 94.358103,196.21253 222.37779,154.64726 89.086568,173.35989 221.43638,148.86013 86.843,150.01469 221.2584,142.99964 87.665786,126.57636 221.8469,137.16606 91.54085,103.44594 223.19179,131.4592 98.401887,81.01921 225.27007,125.9767 108.1315,59.679885 228.04618,120.81238 120.56322,39.79309 231.47262,116.0546 135.48433,21.699094 235.49076,111.78475 152.63953,5.7074906 240.03185,108.07591 171.73529,-7.9080994 245.0182,104.99153 192.44487,-18.91471 250.36448,102.58439 214.41393,-27.124014 255.97921,100.89567 237.26657,-32.395549 261.76633,99.954267 260.61178,-34.639117 267.62682,99.776288 284.0501,-33.81633 273.4604,100.36478 307.18052,-29.941267 279.16727,101.70967 329.60725,-23.08023 284.64976,103.78795 350.94658,-13.350614 289.81408,106.56406 370.83338,-0.91889557 294.57187,109.9905 388.92737,14.002216 298.84171,114.00865 404.91897,31.157415 302.55055,118.54974 418.53456,50.253172 305.63493,123.53608 429.54117,70.962754 308.04207,128.88236 437.75048,92.931813 309.73079,134.49709 443.02201,115.78445 310.6722,140.28421 445.26558,139.12966 310.85018,146.1447 444.4428,162.56799 310.26169,151.97829 440.56773,185.6984 308.91679,157.68515 Z"
inkscape:transform-center-x="-1.5557927e-05"
inkscape:transform-center-y="1.8543187e-05"
transform="matrix(3.4901017,0,0,3.4901017,-674.55653,24.83979)" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -1,108 +0,0 @@
body {
margin: 0;
padding: 0;
background: #AF1F00 url('background.svg') fixed no-repeat center/100%;
color: #FFEF00;
font-family: sans-serif;
display: flex;
flex-direction: column;
justify-content: space-between;
min-height: 100vh;
}
a {
text-decoration: none;
font-weight: bold;
color: #CF3F1F;
}
a:visited {
color: #AF1F00;
}
header, footer {
background-color: #FFEF00;
color: #AF1F00;
text-align: center;
}
header {
margin: 0 0 3rem;
border-bottom: 1rem solid #DFCF00;
}
header h1 {
margin: 0.5rem 0;
padding: 0rem 2rem;
font-family: serif;
}
footer {
margin: 3rem 0 0;
}
footer p {
margin: 0.3rem 0;
}
nav ul {
margin: 0.3rem 0;
padding: 0;
list-style-type: none;
}
nav ul li {
display: inline-block;
margin: 0 2rem;
padding: 0;
}
main {
min-width: 50vh;
max-width: 60rem;
margin: 1rem auto;
padding: 1.5rem 4rem;
background: #FFF;
color: #111;
border-top: 1rem solid #EFDF00;
border-left: 1rem solid #EFDF00;
border-right: 1.5rem solid #DFCF00;
border-bottom: 1.5rem solid #DFCF00;
overflow: auto;
}
main figure {
text-align: center;
}
main figure img {
max-width: 100%;
}
main table {
font-size: 75%;
border-collapse: collapse;
border: 1px solid #555;
}
main table th {
background-color: #555;
color: #FFF;
padding: 0.4rem;
}
main table td {
border: 1px solid #555;
padding: 0.2rem 0.4rem;
}
main h3 code {
margin-left: 0.6rem;
}
.sourceCode .kw {
font-weight: bold;
color: #1F2F6F;
}
.sourceCode .dt {
font-weight: bold;
color: #1F5F2F;
}
.sourceCode .ot {
color: #666;
}
.sourceCode .st {
color: #007F00;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

View File

@ -138,7 +138,7 @@ in rec {
logical-cypher-graph = logical-cypher-graph =
let let
containers = containers =
lib.filterAttrs (_: { role, ... }: lib.filterAttrs (_: { isRouter, role, ... }:
role == "container" role == "container"
) config.site.hosts; ) config.site.hosts;
in in

View File

@ -1,14 +1,12 @@
{ config, lib, pkgs, ... }: { config, pkgs, ... }:
let let
inherit (pkgs) lib runCommand graphviz;
netColor = net: netColor = net:
if net == "core" if net == "core"
then "grey" then "grey"
else if net == "mgmt" else if net == "mgmt"
then "brown" then "brown"
else if net == "roof"
then "orange"
else if net == "flpk"
then "yellow"
else if builtins.elem net [ "c3d2" "serv" "cluster" ] else if builtins.elem net [ "c3d2" "serv" "cluster" ]
then "green" then "green"
else if builtins.match "up.+" net != null || else if builtins.match "up.+" net != null ||
@ -80,13 +78,13 @@ let
} }
''; '';
renderGraph = args@{ name, engine, ... }: renderGraph = args@{ name, engine, ... }:
pkgs.runCommand "${name}.png" { runCommand "${name}.png" {
src = builtins.toFile "${name}.dot" ( src = builtins.toFile "${name}.dot" (
toDot args toDot args
); );
} '' } ''
echo $src echo $src
${pkgs.graphviz-nox}/bin/${engine} -Tpng $src > $out ${graphviz}/bin/${engine} -Tpng $src > $out
''; '';
in rec { in rec {
@ -136,7 +134,7 @@ in rec {
logical-graph = logical-graph =
let let
containers = containers =
lib.filterAttrs (_: { role, ... }: lib.filterAttrs (_: { isRouter, role, ... }:
role == "container" role == "container"
) config.site.hosts; ) config.site.hosts;
in in
@ -160,7 +158,7 @@ in rec {
) (builtins.attrNames containers); ) (builtins.attrNames containers);
}; };
network-graphs = pkgs.runCommand "network-graphs" {} '' network-graphs = runCommand "network-graphs" {} ''
DIR=$out/share/doc/zentralwerk DIR=$out/share/doc/zentralwerk
mkdir -p $DIR mkdir -p $DIR
ln -s ${physical-graph} $DIR/physical.png ln -s ${physical-graph} $DIR/physical.png

View File

@ -1,144 +0,0 @@
{ self, nixpkgs, system, openwrt-imagebuilder }:
let
inherit (self.lib) config;
pkgs = nixpkgs.legacyPackages.${system};
uciConfig = hostName: import ./uci-config.nix { inherit self pkgs hostName; };
modelPackages = {
"tplink_archer-c7-v2" = [
"-kmod-ath10k-ct" "-ath10k-firmware-qca988x-ct-full-htt" "-ath10k-firmware-qca988x-ct"
"kmod-ath10k" "ath10k-firmware-qca988x"
];
"tplink_archer-c7-v5" = [
"-kmod-ath10k-ct" "-ath10k-firmware-qca988x-ct" "-ath10k-firmware-qca988x-ct-full-htt"
"kmod-ath10k" "ath10k-firmware-qca988x"
];
"ubnt_unifiac-lite" = [
"-kmod-ath10k-ct" "-ath10k-firmware-qca988x-ct"
"kmod-ath10k" "ath10k-firmware-qca988x"
];
"ubnt_unifiac-mesh" = [
"-kmod-ath10k-ct" "-ath10k-firmware-qca988x-ct"
"kmod-ath10k" "ath10k-firmware-qca988x"
];
"dir-615-d" = [
# flash size reasons
"-wpad-openssl"
"-tcpdump"
"wpad-wolfssl"
];
};
in rec {
sshScript = hostName:
let
address = config.site.net.mgmt.hosts4.${hostName};
in ''
#! ${pkgs.runtimeShell} -e
ssh root@${address} "cat > /tmp/openwrt-image" < ${buildImage hostName}/openwrt-*-${hostName}-*-sysupgrade.bin
ssh root@${address} "sysupgrade -n /tmp/openwrt-image" || true
# ssh hostkey will have changed after boot
ssh-keygen -R ${address}
'';
buildImage = hostName:
let
hostConfig = config.site.hosts.${hostName};
hasVxlan = builtins.any ({ type, ... }:
type == "vxlan"
) (builtins.attrValues hostConfig.interfaces);
inherit (hostConfig) model;
matches = (openwrt-imagebuilder.lib.profiles {
inherit pkgs;
}).identifyProfiles model;
fallbackProfile =
if model == "dir-615-d"
then (openwrt-imagebuilder.lib.profiles {
inherit pkgs;
release = "19.07.10";
}).identifyProfile model
else if builtins.match "tl-wr[78].*" model != null
then {
release = "18.06.9";
packagesArch = "mips_24kc";
target = "ar71xx";
variant = "tiny";
profile = model;
sha256 = "sha256-P7BJI6n6s53szYXKshnJRKL2fLIYgJLPiq/yd0oRKoE=";
feedsSha256 = {
base.sha256 = "sha256-IbND2snJ1UrDRhvGQIRxzGuSpftQ+AyiWqaVZqbGdHY=";
packages.sha256 = "sha256-18UvzdUL98CranBtzAY7hoUlEvafUdssAQOuqDQi4BU=";
};
}
else null;
build = args:
openwrt-imagebuilder.lib.build (args // {
extraImageName = "zw-${hostName}";
packages = [
# remove unused default .ipk
"-dnsmasq" "-firewall" "-firewall4"
"-ppp" "-ppp-mod-pppoe" "-kmod-ppp" "-kmod-pppoe" "-kmod-pppox"
"-iptables" "-ip6tables" "-kmod-ipt-offload"
"-odhcp6c" "-odhcpd-ipv6only"
"-wpad-basic-mbedtls"
# monitoring
"collectd"
"collectd-mod-iwinfo" "collectd-mod-network"
"collectd-mod-interface" "collectd-mod-load" "collectd-mod-cpu"
"collectd-mod-exec"
] ++ (
if args.variant != "tiny"
then [
# debugging
"htop"
"tcpdump"
# wpa3
"-wpad-basic-wolfssl" "-wpad-mini"
"wpad-openssl"
"usteer"
] else [
# debugging
"tcpdump-mini"
# wpa3
"-wpad-openssl" "-wpad-mini"
"wpad-wolfssl"
]
) ++ nixpkgs.lib.optionals hasVxlan [
"vxlan" "kmod-vxlan"
] ++ modelPackages.${model} or [];
disabledServices = [ "dnsmasq" "uhttpd" ];
files = pkgs.runCommandNoCC "image-files" {} ''
mkdir -p $out/etc/uci-defaults
cat > $out/etc/uci-defaults/99-zentralwerk <<EOF
${uciConfig hostName}
EOF
mkdir -p $out/usr/{bin,sbin}
cp ${./usteer-info.sh} $out/usr/sbin/usteer-info.sh
cp ${./usteer-stats.sh} $out/usr/bin/usteer-stats.sh
chmod +x $out/usr/bin/*.sh $out/usr/sbin/*.sh
'';
});
in
if matches == [] && fallbackProfile != null
then build fallbackProfile
else if matches == []
then builtins.trace "${hostName} (${model}) not supported by OpenWRT"
null
else if builtins.length matches == 1
then build (builtins.elemAt matches 0)
else builtins.trace "${hostName} (${model}) has multiple models!" (
build (builtins.elemAt matches 0)
);
}

View File

@ -1,528 +0,0 @@
{ self, pkgs, hostName }:
with pkgs;
with lib;
let
inherit (self.lib) config;
hostConfig = config.site.hosts.${hostName};
ports = self.lib.getOpenwrtPorts hostConfig.model;
uciDeleteAll = key: ''
while uci -q delete ${key}[-1]; do :; done
'';
openwrtModel = self.lib.getOpenwrtModel hostConfig.model;
hasSwitch =
if hostConfig.model == "ubnt_unifiac-mesh"
# ours don't come with a switch.
then false
else
openwrtModel ? ports
&&
any ({ switch ? null, ... }: switch != null)
(builtins.attrValues openwrtModel.ports);
hasDSA = (
all ({ switch ? null, ... }:
switch == null
) (builtins.attrValues openwrtModel.ports or {})
&&
any ({ port ? null, interface ? null, ... }:
port != null &&
interface != null &&
port == interface
) (builtins.attrValues openwrtModel.ports or {})
) || hostConfig.model == "ubnt_unifi-usg";
portsDoc =
let
portByIndex = builtins.foldl' (result: port:
let
key = if port ? index
then port.index
else if port ? interface
then port.interface
else "How to identify port ${generators.toPretty {} port}?";
in result // {
"${key}" = port;
}
) {} (builtins.attrValues openwrtModel.ports);
in
concatMapStringsSep ", " (index:
"${index}:${
if portByIndex.${index} ? port
then portByIndex.${index}.port
else if portByIndex.${index} ? interface
then portByIndex.${index}.interface
else throw "${hostName}: What is port ${generators.toPretty {} portByIndex.${index}.port}?"
}"
) (
builtins.sort builtins.lessThan (
builtins.attrNames portByIndex
)
);
switchHostInterface =
let
hostPorts = sort builtins.lessThan (
map ({ interface, ... }: interface) (
builtins.attrValues (
filterAttrs (_: { type, ... }: type == "host")
openwrtModel.ports
)
)
);
in if hostPorts == []
then throw "${hostName}: No host ports found for OpenWRT model ${hostConfig.model}"
else builtins.head hostPorts;
switchPortIndices = f:
map ({ index, ... }: index) (
builtins.attrValues (
filterAttrs (_: port: port ? index && f port)
openwrtModel.ports
)
);
trunked = map (index: "${index}t");
# OpenWRT switch ports string ("0t 1t 2 3 4") for a network (VLAN)
switchPortsConfig = net:
concatStringsSep " " (
# Host interface
trunked (switchPortIndices ({ interface ? null, ... }: interface == switchHostInterface))
++
# Access networks
optionals (hostConfig.links ? ${net}) (
builtins.concatMap (port':
switchPortIndices ({ port ? null, ... }: port == port')
) hostConfig.links.${net}.ports
)
++
# Trunk ports
builtins.concatMap (port':
trunked (switchPortIndices ({ port ? null, ... }: port == port'))
) (
builtins.concatMap ({ ports, ... }: ports) (
builtins.attrValues (
filterAttrs (_: { trunk, ... }:
trunk
) hostConfig.links
))
)
);
dsaPorts = net:
unique (
concatMap ({ ports, ... }: ports) (
builtins.filter ({ nets, ... }: builtins.elem net nets)
(builtins.attrValues hostConfig.links)
));
dsaPortType = net: port:
if any ({ ports, trunk, ... }: trunk && builtins.elem port ports) (
builtins.attrValues hostConfig.links
) || hostConfig.links.${net}.trunk or true
then "t"
else "u*";
networkInterfaces = net:
let
inherit (config.site.net.${net}) vlan;
in unique (
builtins.concatMap ({ trunk, ports, switch ? null, ... }:
builtins.concatMap (port:
builtins.concatMap (portData:
if portData ? port && port == portData.port
then [ ((
if portData ? switch
then switchHostInterface
else if portData ? interface
then portData.interface
else throw "${hostName}: Cannot find interface for ${port} on OpenWRT model ${hostConfig.model}"
) + (
if trunk || switch != null
then ".${toString vlan}"
else ""
)) ]
else []
) (builtins.attrValues openwrtModel.ports)
++
optionals (hostConfig.interfaces ? ${port} && vlan != null) [ "${port}.${toString vlan}" ]
) ports
) (
builtins.attrValues (
filterAttrs (link: { nets, ... }:
link == net || builtins.elem net nets
) hostConfig.links
)
)
);
mgmtInterface =
if hasDSA
then "br0.${toString config.site.net.mgmt.vlan}"
else
let
mgmtInterfaces = networkInterfaces "mgmt";
in if builtins.length mgmtInterfaces == 1
then builtins.head mgmtInterfaces
else "br-mgmt";
in
''
# Set root password
echo -e '${hostConfig.password}\n${hostConfig.password}' | passwd
# add ssh pubkeys
${concatMapStrings (sshPubKey: ''
echo "${sshPubKey}" > /etc/dropbear/authorized_keys
'') config.site.sshPubKeys}
# System configuration
${uciDeleteAll "network.@switch_vlan"}
${uciDeleteAll "wireless.@wifi-iface"}
uci set system.@system[0].hostname=${hostName}
uci set dhcp.@dnsmasq[0].enabled=0
uci set system.@system[0].log_ip=${config.site.net.mgmt.hosts4.logging}
uci set system.@system[0].log_proto=udp
${optionalString hasSwitch ''
# Switch config
# Ports ${portsDoc}
${concatMapStrings (net: ''
uci add network switch_vlan
uci set network.@switch_vlan[-1]=switch_vlan
uci set network.@switch_vlan[-1].device='switch0'
uci set network.@switch_vlan[-1].vlan='${toString config.site.net.${net}.vlan}'
uci set network.@switch_vlan[-1].ports='${switchPortsConfig net}'
uci set network.@switch_vlan[-1].comment='${net}'
'') (
sort (net1: net2:
config.site.net.${net1}.vlan < config.site.net.${net2}.vlan
) (
unique (
builtins.concatMap ({ nets, ... }: nets)
(builtins.attrValues hostConfig.links)
)
)
)}
''}
${optionalString hasDSA ''
# DSA
${uciDeleteAll "network.@device"}
uci add network device
uci set network.@device[-1].name='br0'
uci set network.@device[-1].type='bridge'
${concatMapStrings (port: ''
uci add_list network.@device[-1].ports='${port}'
'') (
unique (
builtins.concatMap ({ ports, ... }: ports)
(builtins.attrValues hostConfig.links)
)
)}
uci set network.br0='interface'
uci set network.br0.proto='none'
uci set network.br0.device='br0'
${concatMapStrings (net: ''
uci add network bridge-vlan
uci set network.@bridge-vlan[-1].device='br0'
uci set network.@bridge-vlan[-1].vlan='${toString config.site.net.${net}.vlan}'
${concatMapStrings (port: ''
uci add_list network.@bridge-vlan[-1].ports='${port}:${dsaPortType net port}'
'') (dsaPorts net)}
'') (
sort (net1: net2:
config.site.net.${net1}.vlan < config.site.net.${net2}.vlan
) (
unique (
builtins.concatMap ({ nets, ... }: nets)
(builtins.attrValues hostConfig.links)
)
)
)}
''}
# mgmt network
uci set network.mgmt=interface
${if hasDSA
then ''
uci set network.mgmt.device='br0.${toString config.site.net.mgmt.vlan}'
'' else ''
uci set network.mgmt.ifname='${
if builtins.length (networkInterfaces "mgmt") > 0
then concatStringsSep " " (networkInterfaces "mgmt")
else throw "${hostName}: No interface for mgmt"
}'
''}
uci set network.mgmt.proto=static
${optionalString (hostConfig.interfaces.mgmt.type == "bridge") ''
uci set network.mgmt.type=bridge
''}
uci set network.mgmt.ipaddr=${config.site.net.mgmt.hosts4.${hostName}}
uci set network.mgmt.netmask=${self.lib.netmasks.${toString config.site.net.mgmt.subnet4Len}}
uci set network.mgmt.gateway=${config.site.net.mgmt.hosts4.mgmt-gw}
uci set network.mgmt.ip6addr=${config.site.net.mgmt.hosts6.dn42.${hostName}}/64
uci set network.mgmt.ip6gw=${config.site.net.mgmt.hosts6.dn42.mgmt-gw}
uci -q delete network.mgmt.dns || true
uci add_list network.mgmt.dns=${config.site.net.serv.hosts4.dnscache}
uci add_list network.mgmt.dns=${config.site.net.serv.hosts6.dn42.dnscache}
uci -q delete network.globals.ula_prefix || true
# delete unused networks
${concatMapStrings (net:
optionalString (! hostConfig.interfaces ? ${net}) ''
uci -q delete network.${net} || true
''
) ([ "lan" "wan" "wan6" ] ++ builtins.attrNames config.site.net)}
# bridged and static networks
${concatMapStrings (net:
let
iface = hostConfig.interfaces.${net};
in optionalString (net != "mgmt" && builtins.elem iface.type ["bridge" "phys"]) ''
uci set network.${net}=interface
${optionalString (iface.type == "bridge") ''
uci set network.${net}.type=bridge
uci add network device
uci set network.@device[-1].name='${net}'
uci set network.@device[-1].type='bridge'
''}
uci set network.${net}.proto=static
${if hasDSA
then ''
uci set network.${net}.device='br0.${toString config.site.net.${net}.vlan}'
'' else ''
uci set network.${net}.ifname='${concatStringsSep " " (networkInterfaces net)}'
''}
${optionalString (config.site.net.${net}.mtu != null) ''
uci set network.${net}.mtu=${toString config.site.net.${net}.mtu}
''}
${optionalString (config.site.net.${net}.hosts4 ? ${hostName}) ''
# address in net
uci set network.${net}.ipaddr=${config.site.net.${net}.hosts4.${hostName}}
uci set network.${net}.netmask=${self.lib.netmasks.${toString config.site.net.${net}.subnet4Len}}
''}
${concatMapStrings (hosts6: optionalString (hosts6 ? ${hostName}) ''
uci set network.${net}.ip6addr=${hosts6.${hostName}}/64
'') (builtins.attrValues config.site.net.${net}.hosts6)}
'') (builtins.attrNames hostConfig.interfaces)
}
# vxlan trunks
${concatMapStrings (name:
let
iface = hostConfig.interfaces.${name};
in optionalString (iface.type == "vxlan") ''
uci set network.${name}=interface
uci set network.${name}.proto=vxlan6
uci set network.${name}.peer6addr='${iface.vxlan.peer}'
uci set network.${name}.port=4789
uci set network.${name}.rxcsum=0
uci set network.${name}.txcsum=0
uci set network.${name}.delegate=0
'') (builtins.attrNames hostConfig.interfaces)
}
${uciDeleteAll "wireless.radio"}
uci -q delete wireless.default_radio0 || true
uci -q delete wireless.default_radio1 || true
${concatStrings (imap0 (index: path:
let
radioConfig = hostConfig.wifi.${path};
ifPrefix = if radioConfig.channel < 15
then "wlan2"
else "wlan5";
in ''
uci set wireless.radio${toString index}=wifi-device
uci set wireless.radio${toString index}.type=mac80211
uci set wireless.radio${toString index}.country=DE
uci set wireless.radio${toString index}.band=${radioConfig.band}
uci set wireless.radio${toString index}.channel=${toString radioConfig.channel}
uci set wireless.radio${toString index}.path=${path}
uci set wireless.radio${toString index}.htmode=${radioConfig.htmode}
uci set wireless.radio${toString index}.noscan=1
uci -q delete wireless.radio${toString index}.disabled || true
${concatMapStrings (ssid:
let
ssidConfig = radioConfig.ssids.${ssid};
netConfig = config.site.net.${ssidConfig.net};
# mapping our option to openwrt/hostapd setting
encryption = {
none = "none";
owe = "owe";
wpa2 = "psk2";
wpa3 = "sae-mixed";
}.${ssidConfig.encryption};
ifname =
if ssidConfig.ifname != null
then ssidConfig.ifname
else "${ifPrefix}-${ssidConfig.net}";
pad = len: prefix: s:
if builtins.stringLength s < len
then pad len prefix "${prefix}${s}"
else s;
in ''
uci add wireless wifi-iface
uci set wireless.@wifi-iface[-1].ifname=${ifname}
uci set wireless.@wifi-iface[-1].device=radio${toString index}
uci set wireless.@wifi-iface[-1].ssid='${ssid}'
uci set wireless.@wifi-iface[-1].mode=${ssidConfig.mode}
uci set wireless.@wifi-iface[-1].network=${ssidConfig.net}
uci set wireless.@wifi-iface[-1].mcast_rate=18000
uci set wireless.@wifi-iface[-1].hidden=${if ssidConfig.hidden then "1" else "0"}
uci set wireless.@wifi-iface[-1].encryption='${encryption}'
${if (ssidConfig.psk != null)
then ''
uci set wireless.@wifi-iface[-1].key='${ssidConfig.psk}'
''
else ''
uci -q delete wireless.@wifi-iface[-1].key || true
''}
${lib.optionalString (!ssidConfig.disassocLowAck) ''
uci set wireless.@wifi-iface[-1].disassoc_low_ack='0'
''}
${lib.optionalString (netConfig.wifi.ieee80211rKey != null) ''
# for usteerd
# see https://www.libe.net/en-wlan-roaming#client-steering
# https://openwrt.org/docs/guide-user/network/wifi/usteer#configure_80211k_and_80211v_on_all_ap-nodes
uci set wireless.@wifi-iface[-1].bss_transition=1
uci set wireless.@wifi-iface[-1].wnm_sleep_mode=1
uci set wireless.@wifi-iface[-1].time_advertisement=2
uci set wireless.@wifi-iface[-1].time_zone=GMT0
uci set wireless.@wifi-iface[-1].ieee80211k=1
uci set wireless.@wifi-iface[-1].rrm_neighbor_report=1
uci set wireless.@wifi-iface[-1].rrm_beacon_report=1
# breaks Apple devices connecting to wifi when used together with wpa2/wpa3 mixed mode (sae-mixed)
# uci set wireless.@wifi-iface[-1].ieee80211r=1
# when unset derived from interface MAC
uci set wireless.@wifi-iface[-1].nasid=${pad 12 "0" (toString ((lib.toInt (lib.removePrefix "ap" hostName)) * 65536 + index))}
# when unset derived from the first 4 chars of the md5 hashed SSID
uci set wireless.@wifi-iface[-1].mobility_domain=${pad 4 "0" (lib.toHexString (49920 + netConfig.vlan))}
# https://github.com/openwrt/openwrt/issues/7907
# https://github.com/openwrt/openwrt/commit/2984a0420649733662ff95b0aff720b8c2c19f8a
uci set wireless.@wifi-iface[-1].ft_over_ds=0
# as recommend in 7907 and seems to fairly often trigger while testing
uci set wireless.@wifi-iface[-1].reassociation_deadline=20000
# might be unused if ft_over_ds is not used
uci set wireless.@wifi-iface[-1].ft_bridge=${mgmtInterface}
# otherwise the r0kh/r1kh options below are not applied
uci set wireless.@wifi-iface[-1].ft_psk_generate_local=0
# do not just rely on the monility domain for increased security
# https://forum.openwrt.org/t/802-11r-fast-transition-how-to-understand-that-ft-works/110920/81
uci set wireless.@wifi-iface[-1].r0kh=ff:ff:ff:ff:ff:ff,\*,${netConfig.wifi.ieee80211rKey}
uci set wireless.@wifi-iface[-1].r1kh=00:00:00:00:00:00,00:00:00:00:00:00,${netConfig.wifi.ieee80211rKey}
uci set wireless.@wifi-iface[-1].pmk_r1_push=1
''}
''
) (builtins.attrNames radioConfig.ssids)}
'') (builtins.attrNames hostConfig.wifi))}
uci set usteer.@usteer[0].network=mgmt
uci set usteer.@usteer[0].load_kick_enabled=1
uci set usteer.@usteer[0].load_kick_threshold=67
uci set usteer.@usteer[0].signal_diff_threshold=15
uci set usteer.@usteer[0].load_balancing_threshold=8
uci set usteer.@usteer[0].band_steering_threshold=16
uci commit
# Add hotfixes for MTU settings
cat >/etc/hotplug.d/iface/99-mtu <<__MTU__
#!/bin/sh
${concatMapStrings (net:
optionalString (config.site.net ? ${net} &&
config.site.net.${net}.mtu != null) ''
if [ "\\\$ACTION" = ifup -a "\\\$INTERFACE" = ${net} ]; then
ip link set \\\$DEVICE mtu ${toString config.site.net.${net}.mtu}
fi
'') (builtins.attrNames hostConfig.interfaces)
}
__MTU__
${optionalString hostConfig.wifiOnLink.enable ''
# Cronjob that makes sure WiFi is only visible when server with all
# the gateways is reachable
cat >/etc/crontabs/root <<__CRON__
* * * * * /usr/sbin/wifi-on-link.sh
* * * * * /usr/sbin/usteer-info.sh
__CRON__
cat >/usr/sbin/wifi-on-link.sh <<__SH__
#!/bin/sh
if (ping -c 1 -W 3 ${config.site.net.mgmt.hosts4.mgmt-gw}) ; then
REACHABLE=y
else
REACHABLE=n
fi
if [ "\\\$(cat /sys/class/net/wlan2-pub/operstate)" == "up" ] ; then
UP=y
else
UP=n
fi
if [ -e /sys/class/leds/blue:dome ] ; then
ERROR_LED=/sys/class/leds/blue:dome/brightness
[ \\\$REACHABLE = y ] && echo 0 > \\\$ERROR_LED
[ \\\$REACHABLE = n ] && echo 1 > \\\$ERROR_LED
fi
[ \\\$REACHABLE = y ] && [ \\\$UP = n ] && wifi up
[ \\\$REACHABLE = n ] && [ \\\$UP = y ] && wifi down
exit 0
__SH__
chmod a+rx /usr/sbin/wifi-on-link.sh
/etc/init.d/cron restart
cat > /etc/collectd.conf <<COLLECTD
Hostname "${hostName}"
FQDNLookup false
Interval 10
BaseDir "/var/run/collectd"
Include "/etc/collectd/conf.d"
PIDFile "/var/run/collectd.pid"
PluginDir "/usr/lib/collectd"
TypesDB "/usr/share/collectd/types.db"
LoadPlugin cpu
LoadPlugin load
LoadPlugin interface
LoadPlugin iwinfo
LoadPlugin network
LoadPlugin exec
<Plugin network>
Server "${config.site.net.serv.hosts6.dn42.stats}" "25826"
</Plugin>
<Plugin exec>
Exec "nobody" "/usr/bin/usteer-stats.sh"
</Plugin>
COLLECTD
''}
chmod +x /usr/bin/usteer-stats.sh /usr/sbin/usteer-info.sh
for svc in dnsmasq uhttpd ; do
rm -f /etc/rc.d/*\$svc
/etc/init.d/\$svc stop || true
done
''

View File

@ -1,3 +0,0 @@
#! /bin/sh
[ -p /tmp/usteer-info ] || exit 0
exec /bin/ubus call usteer local_info > /tmp/usteer-info

View File

@ -1,32 +0,0 @@
#! /bin/sh
HOSTNAME=`cat /proc/sys/kernel/hostname`
INTERVAL=60
[ -p /tmp/usteer-info ] || mkfifo /tmp/usteer-info
while true; do
if [ ! -p /tmp/usteer-info ]; then
echo "/tmp/usteer-info went missing!"
exit 1
fi
DATA="$(cat /tmp/usteer-info)"
cd /sys/class/net
for iface in wlan*; do
eval $( echo "$DATA" | jsonfilter \
-e 'LOAD=@["hostapd.'$iface'"].load' \
-e 'NOISE=@["hostapd.'$iface'"].noise' \
-e 'N_ASSOC=@["hostapd.'$iface'"].n_assoc' \
-e 'FREQ=@["hostapd.'$iface'"].freq' \
-e 'ROAM_SOURCE=@["hostapd.'$iface'"].roam_events.source' \
-e 'ROAM_TARGET=@["hostapd.'$iface'"].roam_events.target'
)
echo "PUTVAL \"$HOSTNAME/usteer_local_info-$iface/stations-load\" interval=$INTERVAL N:$LOAD"
echo "PUTVAL \"$HOSTNAME/usteer_local_info-$iface/signal_noise-noise\" interval=$INTERVAL N:$NOISE"
echo "PUTVAL \"$HOSTNAME/usteer_local_info-$iface/stations-n_assoc\" interval=$INTERVAL N:$N_ASSOC"
echo "PUTVAL \"$HOSTNAME/usteer_local_info-$iface/frequency-freq\" interval=$INTERVAL N:$FREQ"
echo "PUTVAL \"$HOSTNAME/usteer_local_info-$iface/transitions-roam_source\" interval=$INTERVAL N:$ROAM_SOURCE"
echo "PUTVAL \"$HOSTNAME/usteer_local_info-$iface/transitions-roam_target\" interval=$INTERVAL N:$ROAM_TARGET"
done
done

View File

@ -57,14 +57,10 @@ nets.each do |net|
end end
exit 1 if collisions > 0 exit 1 if collisions > 0
GROUP_PREFIX = 19 GROUP_PREFIX = 16
groups = {} groups = {}
nets.each do |net| nets.each do |net|
if net.addr.prefix > GROUP_PREFIX
group = net.addr.supernet(GROUP_PREFIX).to_s group = net.addr.supernet(GROUP_PREFIX).to_s
else
group = net.addr.to_s
end
(groups[group] ||= []) << net (groups[group] ||= []) << net
end end
@ -105,9 +101,7 @@ def background_color desc
"#9F9F9F" "#9F9F9F"
when "mgmt" when "mgmt"
"#FF3F3F" "#FF3F3F"
when "roof" when "c3d2"
"#FF4F2F"
when "c3d2", "flpk"
"yellow" "yellow"
when "serv", "cluster" when "serv", "cluster"
"orange" "orange"

View File

@ -1,97 +0,0 @@
{ self, nixpkgs, system }:
with nixpkgs.legacyPackages.${system};
let
config = self.lib.config;
reportHosts = lib.concatMapStrings (hostName:
let
inherit (config.site.hosts.${hostName}) links model location;
linksByPorts = builtins.foldl' (linksByPorts: linkName:
if links.${linkName}.group != null
then
# group ports
linksByPorts // {
${lib.concatMapStringsSep "<br>" (port:
"`${port}`"
) links.${linkName}.ports} = linkName;
}
else
# expand lists of access ports to seperate rows
builtins.foldl' (linksByPorts': port:
linksByPorts' // {
"`${port}`" = linkName;
}
) linksByPorts links.${linkName}.ports
) {} (builtins.attrNames links);
in ''
## ${hostName}
`${model}` @ **${location}**
|Ports|Target|Networks|
|-:|:-:|:-|
${lib.concatMapStrings (ports:
let
linkName = linksByPorts.${ports};
link = links.${linkName};
in ''
|${
lib.optionalString (link.group != null)
"**Group ${toString link.group}**<br>"
}${
ports
}|**${
linkName
}**|${
if link.trunk
then "**Trunk:** "
else "**Access:** "
}${
lib.concatStringsSep ", " (
map (net:
if config.site.net.${net}.vlan != null
then "${net}&nbsp;(`${toString config.site.net.${net}.vlan}`)"
else net
) (builtins.sort (a: b:
let
vlanA = config.site.net.${a}.vlan;
vlanB = config.site.net.${b}.vlan;
in
(
if vlanA == null
then 4096
else vlanA
) < (
if vlanB == null
then 4096
else vlanB
)
) link.nets)
)
}|
'') (lib.naturalSort (
builtins.attrNames linksByPorts
))}
'');
reportRole = role:
reportHosts (
lib.naturalSort (
builtins.filter (hostName:
config.site.hosts.${hostName}.role == role
) (builtins.attrNames config.site.hosts)
)
);
in
writeText "switch-report.md" ''
# Switch Report
${reportRole "switch"}
# Access Point Report
${reportRole "ap"}
''

View File

@ -54,9 +54,7 @@ with lib;
builtins.split "/" netConfig.subnet4 builtins.split "/" netConfig.subnet4
) 2; ) 2;
netmask = self.lib.netmasks.${prefixLength}; netmask = self.lib.netmasks.${prefixLength};
in in ''
if netConfig.vlan != null
then ''
send "vlan ${vlan}\r" send "vlan ${vlan}\r"
expect -- "-vlan${vlan}]" expect -- "-vlan${vlan}]"
send "name ${net}\r" send "name ${net}\r"
@ -72,9 +70,7 @@ with lib;
''} ''}
send "quit\r" send "quit\r"
expect "${hostName}]" expect "${hostName}]"
'' '') (sortNetsByVlan (builtins.attrNames config.site.net))
else ""
) (sortNetsByVlan (builtins.attrNames config.site.net))
} }
${concatMapStrings (name: ${concatMapStrings (name:

View File

@ -1,180 +0,0 @@
{ self, pkgs, hostName, config, hostConfig
, sort, sortBy, sortNetsByVlan
, ... }:
with pkgs;
with lib;
''
#! ${expect}/bin/expect -f
${if hostConfig.firstboot
then ''
spawn sudo ${uucp}/bin/cu -s 19200 -l /dev/ttyUSB0
send "\r"
''
else ''
spawn ${inetutils}/bin/telnet ${config.site.net.mgmt.hosts4.${hostName}}
expect "Password:"
send "${hostConfig.password}\r"
''
}
expect ">"
send "system-view\r"
expect "]"
send "sysname ${hostName}\r"
expect "]"
send "user-interface vty 0 4\r"
expect "ui-vty0-4]"
send "screen-length 0\r"
expect "ui-vty0-4]"
send "user privilege level 3\r"
expect "ui-vty0-4]"
send "set authentication password simple ${hostConfig.password}\r"
expect "ui-vty0-4]"
send "quit\r"
expect "${hostName}]"
send "local-user admin\r"
expect -- "-luser-admin]"
send "password simple ${hostConfig.password}\r"
expect -- "-luser-admin]"
send "quit\r"
expect "${hostName}]"
# Enable logging
send "info-center enable\r"
expect "]"
send "info-center loghost ${config.site.net.mgmt.hosts4.logging} channel loghost facility local6\r"
expect "]"
send "info-center source default channel loghost log level informational\r"
expect "]"
${concatMapStrings (net:
let
netConfig = config.site.net.${net};
vlan = toString netConfig.vlan;
inherit (config.site.net.${net}) hosts4;
hostAddr4 = hosts4.${hostName};
prefixLength = elemAt (
builtins.split "/" netConfig.subnet4
) 2;
netmask = self.lib.netmasks.${prefixLength};
in
if netConfig.vlan != null
then ''
send "vlan ${vlan}\r"
expect -- "-vlan${vlan}]"
send "name ${net}\r"
expect -- "-vlan${vlan}]"
${optionalString (net == "mgmt") ''
# Actually only used for mgmt_vlan, switches are not routers
send "interface Vlan-interface ${vlan}\r"
expect "]"
${optionalString (hosts4 ? ${hostName}) ''
send "ip address ${hostAddr4} ${netmask}\r"
expect "]"
''}
''}
send "quit\r"
expect "${hostName}]"
''
else ""
) (sortNetsByVlan (builtins.attrNames config.site.net))
}
${concatMapStrings (name:
let
linkConfig = hostConfig.links.${name};
isAccess = config.site.net ? ${name};
netConfig = config.site.net.${name};
isTrunk = !isAccess;
isBond = isTrunk && builtins.length linkConfig.ports > 1;
in
if isTrunk
then ''
${optionalString isBond ''
send "link-aggregation group ${linkConfig.group} mode static\r"
expect {
"This aggregation will be modified to static mode. Continue ?" {
send "Y\r"
}
"]" {}
}
send "link-aggregation group ${linkConfig.group} description ${name}\r"
expect "]"
''}
${concatMapStrings (port: ''
send "interface ${port}\r"
expect "]"
send "undo stp edged-port\r"
expect "]"
${if isBond
then ''
send "lacp enable\r"
expect "]"
send "undo port link-aggregation group\r"
expect "]"
send "port link-aggregation group ${linkConfig.group}\r"
'' else ''
send "undo lacp enable\r"
''}
expect "]"
send "jumboframe enable\r"
expect "]"
send "port link-type trunk\r"
expect "]"
# Set dummy default vlan
send "port trunk pvid vlan 4094\r"
expect "]"
# Deconfigure all but mgmt vlan
send "undo port trunk permit vlan 2 to 4094\r"
expect "]"
${concatMapStrings (vlan: ''
send "port trunk permit vlan ${toString vlan}\r"
expect "]"
'') (sort linkConfig.vlans)}
send "undo shutdown\r"
expect "]"
send "quit\r"
expect "${hostName}]"
'') (sort linkConfig.ports)}
'' else
concatMapStrings (port: ''
send "interface ${port}\r"
expect "]"
send "undo port link-aggregation group\r"
expect "]"
send "port link-type access\r"
expect "]"
${if name == "mgmt"
then ''
send "undo port access vlan\r"
expect "]"
'' else ''
send "port access vlan ${toString netConfig.vlan}\r"
expect "]"
''}
send "undo shutdown\r"
expect "]"
send "quit\r"
expect "${hostName}]"
'') (sort linkConfig.ports)
) (sortBy (link: hostConfig.links.${link}.ports)
(builtins.attrNames hostConfig.links)
)}
send "save main\r"
expect "Y/N]"
send "YES\r"
expect "press the enter key):"
send "\r"
expect "]"
send "quit\r"
expect ">"
send "quit\r"
''

View File

@ -37,7 +37,7 @@ with lib;
send "logging facility local6\r" send "logging facility local6\r"
expect "(config)# " expect "(config)# "
# TODO ntp # todo ntp
# timesync sntp # timesync sntp
# ip timep manual {#ntp#} interval 10 # ip timep manual {#ntp#} interval 10
@ -51,9 +51,7 @@ with lib;
builtins.split "/" netConfig.subnet4 builtins.split "/" netConfig.subnet4
) 2; ) 2;
netmask = self.lib.netmasks.${prefixLength}; netmask = self.lib.netmasks.${prefixLength};
in in ''
if netConfig.vlan != null
then ''
send "vlan ${vlan}\r" send "vlan ${vlan}\r"
expect "(vlan-${vlan})#" expect "(vlan-${vlan})#"
@ -83,9 +81,7 @@ with lib;
send "no vlan ${vlan} untagged all\r" send "no vlan ${vlan} untagged all\r"
expect "(config)# " expect "(config)# "
''} ''}
'' '') (sortNetsByVlan (builtins.attrNames config.site.net))
else ""
) (sortNetsByVlan (builtins.attrNames config.site.net))
} }
${concatMapStrings (name: ${concatMapStrings (name:

View File

@ -60,9 +60,7 @@ with lib;
builtins.split "/" netConfig.subnet4 builtins.split "/" netConfig.subnet4
) 2; ) 2;
netmask = self.lib.netmasks.${prefixLength}; netmask = self.lib.netmasks.${prefixLength};
in in ''
if netConfig.vlan != null
then ''
${optionalString (net != "mgmt") '' ${optionalString (net != "mgmt") ''
send "vlan ${vlan}\r" send "vlan ${vlan}\r"
expect "(config-vlan)#" expect "(config-vlan)#"
@ -82,7 +80,6 @@ with lib;
send "exit\r" send "exit\r"
expect "(config)#" expect "(config)#"
'' ''
else ""
) (sortNetsByVlan (builtins.attrNames config.site.net))} ) (sortNetsByVlan (builtins.attrNames config.site.net))}
${concatMapStrings (name: ${concatMapStrings (name:
@ -122,7 +119,7 @@ with lib;
send "exit\r" send "exit\r"
expect "(config)#" expect "(config)#"
'' else '' '' else ''
send "interface range gigabitEthernet ${ports}\r" send "interface range gigabitEthernet 1/0/${ports}\r"
expect "(config-if-range)#" expect "(config-if-range)#"
send "switchport mode access\r" send "switchport mode access\r"
expect "(config-if-range)#" expect "(config-if-range)#"

View File

@ -1,134 +0,0 @@
{ pkgs, hostName, config, hostConfig
, sortBy, sortNetsByVlan
, ... }:
with pkgs;
with lib;
let
configFile = builtins.toFile "junos.config" ''
system {
host-name ${hostName};
time-zone Europe/Berlin;
root-authentication {
encrypted-password "%%HASH%%"; ## SECRET-DATA
ssh-ed25519 "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHGgoLzQMeyX1wjsX/hgVkN//zyfOQPiBRYgO2ajEGH6 root@server2";
}
services {
ssh {
root-login allow;
}
netconf {
ssh;
}
web-management {
http {
interface [ vme.0 vlan.1 ];
}
}
}
}
protocols {
lldp {
interface all;
}
}
virtual-chassis {
no-split-detection;
member 0 {
mastership-priority 255;
}
member 1 {
mastership-priority 255;
}
}
chassis { aggregated-devices { ethernet { device-count 32; } } }
vlans {
${concatMapStrings (net:
let
netName = if net == "mgmt"
then "mgmt-vlan"
else net;
netConfig = config.site.net.${net};
vlan = toString netConfig.vlan;
in
lib.optionalString (netConfig.vlan != null) ''
${netName} {
vlan-id ${vlan};
${lib.optionalString (net == "mgmt") ''
l3-interface vlan.${vlan};
''}
}
''
) (sortNetsByVlan (builtins.attrNames config.site.net))}
}
interfaces {
vlan {
unit ${toString config.site.net.mgmt.vlan} {
family inet {
address ${mgmtAddress}/${toString config.site.net.mgmt.subnet4Len};
}
}
}
${concatMapStrings (name:
let
linkConfig = hostConfig.links.${name};
group = linkConfig.group;
isBond = linkConfig.group != null &&
builtins.length linkConfig.ports > 1;
nets = map (net:
if net == "mgmt"
then "mgmt-vlan"
else net
) linkConfig.nets;
vlanConfig = ''
unit 0 {
family ethernet-switching {
port-mode ${if linkConfig.trunk then "trunk" else "access"};
vlan { members [ ${concatStringsSep " " nets} ]; }
}
}
'';
in
if isBond
then concatMapStrings (port: ''
${port} {
ether-options { 802.3ad ae${group}; }
}
'') (linkConfig.ports) + ''
ae${group} {
aggregated-ether-options { lacp { active; } }
${vlanConfig}
}
''
else concatMapStrings (port: ''
${port} {
${vlanConfig}
}
'') (linkConfig.ports)
) (sortBy (link: hostConfig.links.${link}.ports)
(builtins.attrNames hostConfig.links)
)}
}
'';
configFileWithHash = runCommand "junos.config" {
nativeBuildInputs = [ mkpasswd ];
} ''
HASH=$(echo "${hostConfig.password}" | mkpasswd --method=SHA-512 --stdin)
substitute ${configFile} $out \
--replace "%%HASH%%" "$HASH"
'';
mgmtAddress = config.site.net.mgmt.hosts4.${hostName};
in ''
#! ${runtimeShell} -e
scp ${configFileWithHash} root@${mgmtAddress}:/tmp/junos.config
ssh root@${mgmtAddress} cli <<EOF
configure
load override /tmp/junos.config
commit
EOF
''

View File

@ -1,5 +1,5 @@
# https://www.crc.id.au/real-console-on-linksys-srw2024-switch/ # https://www.crc.id.au/real-console-on-linksys-srw2024-switch/
{ pkgs, hostName, config, hostConfig { self, pkgs, hostName, config, hostConfig
, sort, sortBy, sortNetsByVlan , sort, sortBy, sortNetsByVlan
, ... }: , ... }:
with pkgs; with pkgs;
@ -33,44 +33,29 @@ with lib;
send "vlan database\r" send "vlan database\r"
expect "(config-vlan)# " expect "(config-vlan)# "
${concatMapStrings (net: ${concatMapStrings (net: ''
let send "vlan ${toString config.site.net.${net}.vlan}\r"
netConfig = config.site.net.${net};
in
if netConfig.vlan != null
then ''
send "vlan ${toString netConfig.vlan}\r"
expect "(config-vlan)#" expect "(config-vlan)#"
'' '') (sortNetsByVlan (builtins.attrNames config.site.net))}
else ""
) (sortNetsByVlan (builtins.attrNames config.site.net))}
send "exit\r" send "exit\r"
expect "(config)#" expect "(config)#"
${concatMapStrings (net: ${concatMapStrings (net: ''
let
netConfig = config.site.net.${net};
in
if netConfig.vlan != null
then ''
send "interface vlan ${toString config.site.net.${net}.vlan}\r" send "interface vlan ${toString config.site.net.${net}.vlan}\r"
expect "(config-if)#" expect "(config-if)#"
send "name ${net}\r" send "name ${net}\r"
expect "(config-if)#" expect "(config-if)#"
send "exit\r" send "exit\r"
expect "(config)#" expect "(config)#"
'' '') (sortNetsByVlan (builtins.attrNames config.site.net))}
else ""
) (sortNetsByVlan (builtins.attrNames config.site.net))}
${concatMapStrings (name: ${concatMapStrings (name:
let let
linkConfig = hostConfig.links.${name}; linkConfig = hostConfig.links.${name};
isAccess = config.site.net ? ${name};
netConfig = config.site.net.${name}; netConfig = config.site.net.${name};
isTrunk = linkConfig.trunk; isTrunk = !isAccess;
isBond = builtins.length linkConfig.ports > 1 && isBond = isTrunk && builtins.length linkConfig.ports > 1;
# not named like a net
(!config.site.net ? ${name});
vlans = concatStringsSep "," (map toString (sort linkConfig.vlans)); vlans = concatStringsSep "," (map toString (sort linkConfig.vlans));
ports = concatStringsSep "," linkConfig.ports; ports = concatStringsSep "," linkConfig.ports;
in in
@ -109,31 +94,6 @@ with lib;
send "exit\r" send "exit\r"
expect "(config)#" expect "(config)#"
'') linkConfig.ports '') linkConfig.ports
else if isBond
then
if builtins.length linkConfig.vlans != 1
then throw "Cannot configure non-trunked port with multiple vlans"
else ''
send "interface range ethernet ${ports}\r"
expect "(config-if)#"
send "channel-group ${linkConfig.group} mode auto\r"
expect "(config-if)#"
send "interface port-channel ${linkConfig.group}\r"
expect "(config-if)#"
send "exit\r"
send "interface port-channel ${linkConfig.group}\r"
expect "(config-if)#"
send "switchport trunk allowed vlan remove all\r"
expect "(config-if)#"
send "switchport mode access\r"
expect "(config-if)#"
send "switchport access vlan ${toString (builtins.head linkConfig.vlans)}\r"
expect "(config-if)#"
send "exit\r"
expect "(config)#"
''
else concatMapStrings (port: '' else concatMapStrings (port: ''
send "interface ethernet ${port}\r" send "interface ethernet ${port}\r"
expect "(config-if)#" expect "(config-if)#"

View File

@ -17,13 +17,6 @@ rec {
else ra < rb else ra < rb
); );
sortNetsByVlan = builtins.sort (net1: net2: sortNetsByVlan = builtins.sort (net1: net2:
let config.site.net.${net1}.vlan < config.site.net.${net2}.vlan
vlan1 = config.site.net.${net1}.vlan;
vlan2 = config.site.net.${net2}.vlan;
in if vlan1 == null
then true
else if vlan2 == null
then false
else vlan1 < vlan2
); );
} }

View File

@ -1,24 +0,0 @@
{ self, nixpkgs, system }:
with nixpkgs.legacyPackages.${system};
let
config = self.lib.config;
in
writeText "vlan-report.md" ''
# VLAN Report
${lib.concatMapStrings (net: ''
## ${net}${lib.optionalString (config.site.net.${net}.vlan != null) " (VLAN ${toString config.site.net.${net}.vlan})"}
${lib.concatStringsSep "\n" (
lib.concatMap (host:
map (target: "- ${host} -> ${target}") (
builtins.attrNames (
lib.filterAttrs (_: { nets, ... }:
lib.elem net nets
) config.site.hosts.${host}.links
)
)
) (lib.attrNames config.site.hosts)
)}
'') (lib.attrNames config.site.net)}
''

5985
openwrt/tl-wr841-v10.config Normal file

File diff suppressed because it is too large Load Diff

5849
openwrt/tl-wr841-v11.config Normal file

File diff suppressed because it is too large Load Diff

6002
openwrt/tl-wr841-v8.config Normal file

File diff suppressed because it is too large Load Diff