# SPDX-FileCopyrightText: 2020 Luke Granger-Brown # # SPDX-License-Identifier: Apache-2.0 { depot, lib, pkgs, config, ... }: let inherit (depot.ops) secrets; inherit (lib) mkMerge mkForce; in { imports = [ # We include this just so it sets some sysctls and firewall settings. ../lib/bgp.nix ../lib/erbium.nix ]; config = mkMerge [ { boot.initrd.availableKernelModules = [ "sd_mod" "ahci" "usb_storage" "usbhid" ]; boot.kernelParams = [ "mitigations=off" ]; fileSystems = { "/" = { device = "/dev/disk/by-uuid/fc964ef6-e3d0-4472-bc0e-f96f977ebf11"; fsType = "ext4"; }; "/boot" = { device = "/dev/disk/by-uuid/AB36-5BE4"; fsType = "vfat"; }; }; nix.settings.max-jobs = lib.mkDefault 4; # Use the systemd-boot EFI boot loader. boot.loader.systemd-boot.enable = true; boot.loader.efi.canTouchEfiVariables = true; # Networking! networking = { # Routing tables: # bgp (150) -- contains default routes over WG tunnels # wg-ee (152) -- contains default routes over WG tunnels # wg-gnet (153) -- contains default routes over WG tunnels # ee (201) -- table contains a default route via EE # vm (202) -- table contains a default route via VM # gnet (203) -- table contains a default route via gnetwork # main (254) -- basically empty hostName = "swann"; # Define your hostname. domain = "int.as205479.net"; nameservers = ["8.8.8.8" "8.8.4.4"]; useNetworkd = true; interfaces = { lo = { ipv4.addresses = [ { address = "127.0.0.1"; prefixLength = 8; } { address = "92.118.30.254"; prefixLength = 32; } { address = "92.118.30.253"; prefixLength = 32; } ]; }; en-gnet = { useDHCP = true; ipv4.addresses = [ { address = "192.168.201.2"; prefixLength = 24; } ]; # Additional options configured in networkd. }; en-ee = { useDHCP = true; ipv4.addresses = [ { address = "10.42.0.2"; prefixLength = 24; } ]; # Additional options configured in networkd. }; br-internal = { ipv4.addresses = [ { address = "192.168.1.1"; prefixLength = 23; } { address = "92.118.30.17"; prefixLength = 28; } ]; ipv6.addresses = [ { address = "2a09:a443::1"; prefixLength = 64; } { address = "2a09:a443:1::1"; prefixLength = 48; } ]; }; vl-eduroam = { ipv4.addresses = [ { address = "192.168.10.1"; prefixLength = 24; } ]; ipv6.addresses = [ { address = "2a09:a443:2::1"; prefixLength = 64; } { address = "2a09:a443:3::1"; prefixLength = 48; } ]; }; }; }; systemd.network = let hexToInt = h: (builtins.fromTOML "h = ${h}").h; physicalNetwork = rtID: wireguardFwmark: extraRules: { dhcpV4Config.RouteTable = rtID; ipv6AcceptRAConfig.RouteTable = rtID; routingPolicyRules = [{ routingPolicyRuleConfig = { Family = "both"; FirewallMark = hexToInt wireguardFwmark; Priority = 10000; Table = rtID; }; }] ++ extraRules; }; wireguardNetwork = { linkName, relativePriority, rtID, v4Linknet, v6Linknet }: { matchConfig.Name = linkName; routes = let replaceV4Octet = v4: fn: let pieces = builtins.match ''(([0-9]+\.){3})([0-9]+)'' v4; in "${builtins.elemAt pieces 0}${toString (fn (lib.toInt (builtins.elemAt pieces 2)))}"; replaceV6Octet = v6: fn: let pieces = builtins.match ''^(([0-9a-f]+:+)+)([0-9a-f]*)$'' v6; in "${builtins.elemAt pieces 0}${lib.toHexString (fn (hexToInt "0x${builtins.elemAt pieces 2}"))}"; in [ { routeConfig = { Destination = "${v4Linknet}/31"; Table = rtID; }; } { routeConfig = { Gateway = replaceV4Octet v4Linknet (n: n + 1); Table = rtID; }; } { routeConfig = { Destination = "${replaceV6Octet v6Linknet (n: 0)}/112"; Table = rtID; }; } { routeConfig = { Gateway = replaceV6Octet v6Linknet (n: n + 1); Table = rtID; }; } ]; networkConfig = { Address = [ "${v4Linknet}/31" "${v6Linknet}/112" ]; }; routingPolicyRules = [ (tailscaleRule (relativePriority + 5000) rtID) # Allow picking destination by source IP. { routingPolicyRuleConfig = { Family = "ipv4"; From = v4Linknet; Priority = 10010; Table = rtID; }; } { routingPolicyRuleConfig = { Family = "ipv6"; From = v6Linknet; Priority = 10010; Table = rtID; }; } ]; }; tailscaleRule = priority: table: { # Route Tailscale (fwmark 0x80000) via Wireguard first. routingPolicyRuleConfig = { Family = "both"; FirewallMark = hexToInt "0x80000"; # Should be "0x80000/0xff0000" Priority = priority; Table = table; }; }; in let routeTables = { bgp = 150; wg-ee = 152; wg-gnet = 153; wg-eta = 160; ee = 201; gnet = 203; }; in { enable = true; config.routeTables = routeTables; networks."50-wg-tuvok-ee" = wireguardNetwork { linkName = "wg-tuvok-ee"; relativePriority = 3; rtID = routeTables.wg-ee; v4Linknet = "92.118.30.2"; v6Linknet = "2a09:a442::2:1"; }; networks."50-wg-tuvok-gnet" = wireguardNetwork { linkName = "wg-tuvok-gnet"; relativePriority = 1; rtID = routeTables.wg-gnet; v4Linknet = "92.118.30.4"; v6Linknet = "2a09:a442::3:1"; }; networks."50-wg-eta" = wireguardNetwork { linkName = "wg-eta"; relativePriority = 10; rtID = routeTables.wg-eta; v4Linknet = "169.254.2.1"; v6Linknet = "fe80:1234::b"; }; networks."40-lo" = { routingPolicyRules = let viaMain = priority: to: { routingPolicyRuleConfig = { To = to; Table = "main"; Priority = priority; }; }; blackhole = fwmark: { routingPolicyRuleConfig = { Family = "both"; FirewallMark = hexToInt fwmark; Priority = 10001; Type = "unreachable"; }; }; in [ (tailscaleRule 5000 150) # Blackhole connections that should be routed over individual interfaces. (blackhole "0xdead") (blackhole "0xbeef") (blackhole "0xcafe") # RFC 1918 via main table. (viaMain 10020 "192.168.0.0/16") (viaMain 10021 "10.0.0.0/8") (viaMain 10022 "172.16.0.0/12") # and the linknets. (viaMain 10023 "92.118.30.0/24") (viaMain 10024 "2a09:a442::1:0/112") (viaMain 10025 "2a09:a442::2:0/112") (viaMain 10026 "2a09:a442::3:0/112") { # Catch-all "go via WG" routingPolicyRuleConfig = { Family = "both"; Priority = 10080; Table = routeTables.bgp; }; } ]; }; networks."40-en-ee" = (physicalNetwork routeTables.ee "0xdead" [{ routingPolicyRuleConfig = { # add-on.ee.co.uk goes via EE. To = "82.192.97.153/32"; Table = routeTables.ee; Priority = 10031; }; } { routingPolicyRuleConfig = { # as does anything from 10.42.0.0/24. From = "10.42.0.0/24"; Table = routeTables.ee; Priority = 10031; }; }]) // { linkConfig.RequiredForOnline = "no"; routes = [{ routeConfig = { Gateway = "10.42.0.1"; Destination = "0.0.0.0/0"; Table = routeTables.ee; }; } { routeConfig = { Destination = "10.42.0.0/24"; Table = routeTables.ee; }; }]; }; networks."40-en-gnet" = (physicalNetwork routeTables.gnet "0xcafe" [{ # Catch-all mop-up rule at the end. routingPolicyRuleConfig = { Family = "both"; Priority = 32768; Table = routeTables.gnet; }; }]); networks."40-br-internal" = { networkConfig.VLAN = [ "vl-eduroam" ]; }; networks."40-en-int-eth" = { matchConfig.Name = "en-int-eth"; networkConfig.Bridge = "br-internal"; }; networks."40-en-int-sfp" = { matchConfig.Name = "en-int-sfp"; networkConfig.Bridge = "br-internal"; }; netdevs = let wireguard = { name, listenPort, privateKey, endpoint, publicKey, fwmark }: { netdevConfig = { Name = name; Kind = "wireguard"; Description = "WireGuard tunnel ${name}"; }; wireguardConfig = { ListenPort = listenPort; PrivateKeyFile = pkgs.writeText "${name}" privateKey; # TODO: PrivateKeyFile FirewallMark = hexToInt fwmark; RouteTable = "off"; }; wireguardPeers = [{ wireguardPeerConfig = { Endpoint = endpoint; PublicKey = publicKey; AllowedIPs = [ "0.0.0.0/0" "::/0" ]; }; }]; }; tuvokWireguard = args: wireguard (args // { privateKey = secrets.wireguard.tuvok-swann.swann.privateKey; publicKey = secrets.wireguard.tuvok-swann.tuvok.publicKey; }); in { "40-wg-tuvok-ee" = tuvokWireguard { name = "wg-tuvok-ee"; listenPort = 51821; #endpoint = "92.118.28.252:51821"; endpoint = "[2a09:a441::f00f]:51821"; fwmark = "0xdead"; }; "40-wg-tuvok-gnet" = tuvokWireguard { name = "wg-tuvok-gnet"; listenPort = 51822; endpoint = "92.118.28.252:51822"; fwmark = "0xcafe"; }; "50-wg-eta" = { netdevConfig = { Name = "wg-eta"; Kind = "wireguard"; Description = "WireGuard tunnel wg-eta"; }; wireguardConfig = { ListenPort = 51830; PrivateKeyFile = config.my.vault.secrets.wg-eta-private.path; RouteTable = "off"; FirewallMark = hexToInt "0xcafe"; # over gnet }; wireguardPeers = [{ wireguardPeerConfig = { Endpoint = "shenfield-mythic.i.eta.st:51825"; #PublicKey = config.my.vault.secrets.wg-eta-public.path; PublicKey = "JDelaz8FQBtJBRVd9CMYikO/25gKipYgfyXtjL6jgS8="; AllowedIPs = [ "0.0.0.0/0" "::/0" ]; }; }]; }; "20-br-internal" = { netdevConfig = { Name = "br-internal"; Kind = "bridge"; Description = "Bridge br-internal"; }; extraConfig = '' [Bridge] VLANFiltering=false MulticastQuerier=true MulticastSnooping=false STP=true VLANProtocol=802.1q MulticastIGMPVersion=3 ''; }; "25-vl-eduroam" = { netdevConfig = { Name = "vl-eduroam"; Kind = "vlan"; Description = "Eduroam VLAN on br-internal"; }; vlanConfig = { Id = 100; }; }; }; }; my.vault.secrets = { wg-eta-public = { group = "systemd-network"; template = '' {{- with secret "kv/apps/wireguard/swann" -}} {{- .Data.data.publicKeyFromEta -}} {{- end -}} ''; }; wg-eta-private = { group = "systemd-network"; template = '' {{- with secret "kv/apps/wireguard/swann" -}} {{- .Data.data.privateKeyToEta -}} {{- end -}} ''; }; }; services.mstpd.enable = true; my.ip.tailscale = "100.102.224.95"; my.ip.tailscale6 = "fd7a:115c:a1e0:ab12:4843:cd96:6266:e05f"; services.udev.extraRules = '' ATTR{address}=="e4:3a:6e:16:07:63", DRIVERS=="?*", NAME="en-ee" ATTR{address}=="e4:3a:6e:16:07:64", DRIVERS=="?*", NAME="en-gnet" ATTR{address}=="e4:3a:6e:16:07:67", DRIVERS=="?*", NAME="en-int-eth" ATTR{address}=="e4:3a:6e:16:08:bc", DRIVERS=="?*", NAME="en-int-sfp" ''; boot.kernel.sysctl = { "net.ipv4.ip_forward" = "1"; "net.ipv6.conf.default.forwarding" = "1"; "net.ipv6.conf.all.forwarding" = "1"; "net.ipv6.conf.en-ee.accept_ra" = "2"; "net.ipv6.conf.en-gnet.accept_ra" = "2"; }; networking.nat = { enable = true; internalInterfaces = ["br-internal"]; externalInterface = "en-gnet"; extraCommands = '' # Send PS5 RTMP to totoro instead. # See DHCP static lease. iptables -w -t nat -A nixos-nat-pre --src 92.118.30.18 -p tcp --dport 1935 -j DNAT --to-destination 192.168.1.40 # NAT packets going over EE plain. iptables -w -t nat -A nixos-nat-post -m mark --mark 1 -o en-ee -j MASQUERADE # NAT packets going over GNetwork plain. iptables -w -t nat -A nixos-nat-post -m mark --mark 1 -o en-gnet -j MASQUERADE # SNAT packets we're sending over tunnels. iptables -w -t nat -A nixos-nat-post -m mark --mark 1 -o wg-tuvok-ee -j SNAT --to-source 92.118.30.254 iptables -w -t nat -A nixos-nat-post -m mark --mark 1 -o wg-tuvok-gnet -j SNAT --to-source 92.118.30.254 # eduroam # > mark incoming eduroam packets iptables -w -t nat -A nixos-nat-pre -i vl-eduroam -j MARK --set-mark 2 # > NAT packets going out directly. iptables -w -t nat -A nixos-nat-post -m mark --mark 2 -o en-ee -j MASQUERADE iptables -w -t nat -A nixos-nat-post -m mark --mark 2 -o en-gnet -j MASQUERADE # > NAT packets going over tunnels. iptables -w -t nat -A nixos-nat-post -m mark --mark 2 -o wg-tuvok-ee -j SNAT --to-source 92.118.30.253 iptables -w -t nat -A nixos-nat-post -m mark --mark 2 -o wg-tuvok-gnet -j SNAT --to-source 92.118.30.253 ''; }; services.erbium = { enable = false; # TODO: true; package = depot.nix.pkgs.erbium; settings = { addresses = [ # internal "192.168.1.0/24" "92.118.30.16/28" "2a09:a443::/64" "2a09:a443:1::/48" # eduroam "192.168.10.0/24" "2a09:a443:2::/64" "2a09:a443:3::/48" ]; dns-servers = [ "$self4" "$self6" ]; api-listeners = [ "[::1]:9968" ]; dns-listeners = [ "[::1]:11153" ]; # if we don't specify something then erbium crashes router-advertisements = let baseline = { mtu = 1420; lifetime = "1h"; reachable = "20m"; }; baselinePrefix = { on-link = true; autonomous = true; valid = "30d"; preferred = "7d"; }; in { br-internal = baseline // { dns-servers.addresses = [ "2a09:a443::1" ]; dns-search.domains = [ "house.as205479.net" ]; prefixes = [(baselinePrefix // { prefix = "2a09:a443::/64"; }) (baselinePrefix // { prefix = "2a09:a443:1::/48"; autonomous = false; })]; }; vl-eduroam = baseline // { dns-servers.addresses = [ "2a09:a443:2::1" ]; dns-search.domains = [ "eduroam.as205479.net" ]; prefixes = [(baselinePrefix // { prefix = "2a09:a443:2::/64"; }) (baselinePrefix // { prefix = "2a09:a443:3::/48"; autonomous = false; })]; }; }; dhcp-policies = [ # public internal { apply-subnet = "92.118.30.16/28"; apply-domain-name = "house-ext.as205479.net"; apply-dns-servers = [ "92.118.30.17" ]; apply-routers = [ "92.118.30.17" ]; apply-mtu = 1420; policies = [{ match-hardware-address = "bc:33:29:26:01:5c"; apply-host-name = "ps5"; apply-address = "92.118.30.18"; }]; } # private internal { match-subnet = "192.168.1.0/24"; apply-range.start = "192.168.1.100"; apply-range.end = "192.168.1.200"; apply-domain-name = "house.as205479.net"; apply-dns-servers = [ "192.168.1.1" ]; apply-routers = [ "192.168.1.1" ]; apply-mtu = 1420; policies = [{ match-hardware-address = "40:8d:5c:1f:e8:68"; apply-host-name = "totoro"; apply-address = "192.168.1.40"; } { match-hardware-address = "52:54:00:cf:cd:94"; apply-host-name = "totoro-pfsense"; apply-address = "192.168.1.41"; } { match-hardware-address = "00:0d:5d:1b:14:ba"; apply-host-name = "kvm"; apply-address = "192.168.1.50"; } { match-hardware-address = "9c:93:4e:ad:1f:7b"; apply-host-name = "printer-xerox"; apply-address = "192.168.1.51"; } { match-hardware-address = "84:39:be:77:65:52"; apply-host-name = "qvmpc6552"; apply-address = "192.168.1.60"; }]; } # eduroam { match-subnet = "192.168.10.0/24"; apply-range.start = "192.168.10.10"; apply-range.end = "192.168.10.200"; apply-domain-name = "eduroam.as205479.net"; apply-dns-servers = [ "192.168.10.1" ]; apply-routers = [ "192.168.10.1" ]; apply-mtu = 1420; } ]; }; }; networking.firewall = { interfaces.br-internal = { allowedTCPPorts = [ 8080 6789 # Unifi 53 # DNS ]; allowedUDPPorts = [ 3478 10001 # Unifi 53 # DNS 69 # TFTP 80 # HTTP ]; }; interfaces.vl-eduroam = { allowedTCPPorts = [ 53 # DNS ]; allowedUDPPorts = [ 53 # DNS ]; }; interfaces.en-ee = { allowedUDPPorts = [ 51821 ]; }; interfaces.en-gnet = { allowedUDPPorts = [ 51822 ]; }; interfaces.wg-tuvok-ee = { allowedUDPPorts = [ 3784 # BFD ]; }; interfaces.wg-tuvok-gnet = { allowedUDPPorts = [ 3784 # BFD ]; }; interfaces.wg-eta = { allowedTCPPorts = [ 179 # BGP ]; }; extraCommands = '' ip46tables -F FORWARD ip46tables -N ts-forward || true ip46tables -A FORWARD -j ts-forward iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1360 ip6tables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1360 ip46tables -A FORWARD -i vl-eduroam -o wg-tuvok-ee -j ACCEPT ip46tables -A FORWARD -i vl-eduroam -o wg-tuvok-gnet -j ACCEPT ip46tables -A FORWARD -i vl-eduroam -o wg-eta -j ACCEPT ip46tables -A FORWARD -i vl-eduroam -m state --state NEW,RELATED -j REJECT ''; }; environment.systemPackages = with pkgs; [ ethtool conntrack-tools minicom screen (writeShellApplication { name = "bridge-stp"; runtimeInputs = [ mstpd ]; text = '' BRIDGES=("br-internal") for BRIDGE in "''${BRIDGES[@]}"; do if [[ "$BRIDGE" = "$1" ]]; then if [[ "$2" = "start" ]]; then mstpctl addbridge "$BRIDGE" exit 0 elif [[ "$2" = "stop" ]]; then mstpctl delbridge "$BRIDGE" exit 0 fi exit 1 fi done exit 1 ''; }) ]; services.coredns = { enable = true; config = '' .:53 { bind 192.168.1.1 92.118.30.17 192.168.10.1 127.0.0.253 2a09:a443::1 2a09:a443:1::1 2a09:a443:2::1 2a09:a443:3::1 acl { allow net 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 127.0.0.0/8 100.64.0.0/10 2a09:a443::/32 92.118.30.0/24 block } hosts /dev/null { #216.239.38.120 stadia.google.com stadia.com fallthrough } loadbalance forward . tls://8.8.8.8 tls://8.8.4.4 { tls_servername dns.google } cache { success 4096 denial 1024 prefetch 512 } prometheus :9153 errors log } ''; }; systemd.services.coredns = { wants = [ "systemd-networkd-wait-online.service" ]; after = [ "systemd-networkd-wait-online.service" ]; }; my.prometheus.additionalExporterPorts.coredns = 9153; networking.resolvconf.extraConfig = '' name_servers='127.0.0.253' ''; services.prometheus.exporters.smokeping = { enable = true; hosts = [ "8.8.8.8" # Google Public DNS "2001:4860:4860::8888" "youtube.com" "ads.google.com" "google.com" "1.1.1.1" # Cloudflare DNS "2606:4700:4700::1111" "twitter.com" "store.steampowered.com" "api.steampowered.com" # "euw1.api.riotgames.com" # League of Legends EUW "eu.battle.net" "185.60.112.157" "185.60.112.158" # Diablo 3/HotS/Hearthstone "185.60.114.159" # Overwatch # BFOB TS "2a01:a500:85:3::2" "37.9.61.53" # lukegb01.ring.nlnog.net "2a09:a441::13" "92.118.28.13" ]; }; services.bird2 = { enable = true; config = '' router id 92.118.30.254; protocol kernel { kernel table 150; metric 0; ipv4 { import none; export all; }; }; protocol kernel { kernel table 150; metric 0; ipv6 { import none; export all; }; }; protocol device {}; protocol static export4 { ipv4 {}; route 0.0.0.0/0 via 92.118.30.1 bfd { # Virgin Media preference = 100; }; route 0.0.0.0/0 via 92.118.30.3 bfd { # EE preference = 10; }; route 0.0.0.0/0 via 92.118.30.5 bfd { # GNetwork preference = 200; }; route 92.118.30.0/24 unreachable { bgp_ext_community.add((ro, 205479, 1000)); # export this }; route 92.118.30.16/28 via "br-internal"; route 92.118.30.254/32 via "lo"; route 92.118.30.253/32 via "lo"; # route 92.118.30.0/31 via "wg-tuvok-vm"; route 92.118.30.2/31 via "wg-tuvok-ee"; route 92.118.30.4/31 via "wg-tuvok-gnet"; }; protocol static export6 { ipv6 {}; route ::/0 via 2a09:a442::1:2 bfd { # Virgin Media preference = 100; krt_prefsrc = 2a09:a443::1; }; route ::/0 via 2a09:a442::2:2 bfd { # EE preference = 10; krt_prefsrc = 2a09:a443::1; }; route ::/0 via 2a09:a442::3:2 bfd { # GNetwork preference = 200; krt_prefsrc = 2a09:a443::1; }; # Covering route... route 2a09:a443::/64 via "br-internal"; route 2a09:a443:1::/48 via "br-internal"; route 2a09:a443:2::/64 via "vl-eduroam"; route 2a09:a443:3::/48 via "vl-eduroam"; route 2a09:a443::/32 unreachable { bgp_ext_community.add((ro, 205479, 1000)); # export this }; }; protocol bfd { interface "*" { min rx interval 10ms; min tx interval 50ms; idle tx interval 1s; multiplier 20; }; neighbor 92.118.30.1; neighbor 2a09:a442::1:2; neighbor 92.118.30.3; neighbor 2a09:a442::2:2; neighbor 92.118.30.5; neighbor 2a09:a442::3:2; }; protocol bgp eta4 { local 169.254.2.1 as 205479; neighbor 169.254.2.0 as 213185; interface "wg-eta"; ipv4 { export filter { if source != RTS_STATIC then reject; if ! ((ro, 205479, 1000) ~ bgp_ext_community) then reject; bgp_ext_community.delete([(ro, 205479, *)]); accept; }; import filter { if ! (net ~ [ 44.31.189.0/24 ]) then reject; accept; }; next hop self; }; }; protocol bgp eta6 { local fe80:1234::b as 205479; neighbor fe80:1234::a as 213185; interface "wg-eta"; ipv6 { export filter { if source != RTS_STATIC then reject; if ! ((ro, 205479, 1000) ~ bgp_ext_community) then reject; bgp_ext_community.delete([(ro, 205479, *)]); accept; }; import filter { if ! (net ~ [ 2a0d:1a40:7553::/48{48,64} ]) then reject; accept; }; next hop self; }; }; ''; }; systemd.services.prometheus-bird-exporter.serviceConfig.ExecStart = lib.mkForce '' ${depot.pkgs.prometheus-bird-exporter-lfty}/bin/bird_exporter \ -web.listen-address 0.0.0.0:9324 \ -bird.socket /var/run/bird/bird.ctl \ -bird.v2=true \ -format.new=true ''; systemd.services.ee-scrape-data = let scriptFile = ./ee-scrape-data.py; python = pkgs.python3.withPackages (pm: with pm; [ requests beautifulsoup4 html5lib ]); in { enable = true; serviceConfig = { Type = "oneshot"; ExecStart = "${python}/bin/python ${scriptFile} /run/prometheus-textfile-exports/ee-scrape-data.prom"; }; }; systemd.timers.ee-scrape-data = { enable = true; wantedBy = [ "multi-user.target" ]; timerConfig = { OnBootSec = "2m"; OnUnitInactiveSec = "1m"; RandomizedDelaySec = "20"; }; }; system.stateVersion = "21.03"; } { # Minimize writes to storage. boot.tmp.useTmpfs = true; services.journald.extraConfig = '' Storage=volatile ''; systemd.services.tailscaled.environment.TS_LOGS_DIR = "/var/run/tailscale"; } (lib.mkIf (!config.services.erbium.enable) { services.radvd = { enable = true; config = '' interface br-internal { AdvSendAdvert on; AdvLinkMTU 1420; # Wireguard AdvManagedFlag on; RDNSS 2a09:a443::1 {}; DNSSL house.as205479.net {}; prefix 2a09:a443::/64 { AdvOnLink on; AdvAutonomous on; }; prefix 2a09:a443:1::/48 { AdvOnLink on; AdvAutonomous off; }; }; interface vl-eduroam { AdvSendAdvert on; AdvLinkMTU 1420; # Wireguard AdvManagedFlag on; RDNSS 2a09:a443:2::1 {}; DNSSL eduroam.as205479.net {}; prefix 2a09:a443:2::/64 { AdvOnLink on; AdvAutonomous on; }; prefix 2a09:a443:3::/48 { AdvOnLink on; AdvAutonomous off; }; }; ''; }; services.atftpd = { enable = true; }; services.nginx = { enable = true; virtualHosts."192.168.1.1".root = "/srv/tftp"; }; services.kea = { dhcp4.enable = true; dhcp4.settings = { interfaces-config.interfaces = ["br-internal" "vl-eduroam"]; lease-database = { type = "memfile"; persist = true; name = "/var/lib/kea/dhcp4.leases"; }; reservations-global = true; reservations = [{ hw-address = "40:8d:5c:1f:e8:68"; ip-address = "192.168.1.40"; hostname = "totoro"; } { hw-address = "52:54:00:cf:cd:94"; ip-address = "192.168.1.41"; hostname = "totoro-pfsense"; } { hw-address = "00:0d:5d:1b:14:ba"; ip-address = "192.168.1.50"; hostname = "kvm"; } { hw-address = "9c:93:4e:ad:1f:7b"; ip-address = "192.168.1.51"; hostname = "printer-xerox"; } { hw-address = "e8:ed:f3:6a:b9:24"; ip-address = "192.168.1.52"; hostname = "phone-lukegb-desk"; option-data = [{ name = "tftp-server-name"; data = "192.168.1.1"; }]; } { hw-address = "bc:33:29:26:01:5c"; ip-address = "92.118.30.18"; hostname = "ps5"; } { hw-address = "84:39:be:77:65:52"; ip-address = "192.168.1.60"; hostname = "qvmpc6552"; }]; subnet4 = [{ subnet = "192.168.1.0/24"; pools = [{ pool = "192.168.1.100 - 192.168.1.200"; }]; option-data = [{ name = "routers"; data = "192.168.1.1"; } { name = "domain-name-servers"; data = "192.168.1.1"; } { name = "domain-name"; data = "house.as205479.net"; } { name = "interface-mtu"; data = "1420"; }]; } { subnet = "92.118.30.16/28"; option-data = [{ name = "routers"; data = "92.118.30.17"; } { name = "domain-name-servers"; data = "92.118.30.17"; } { name = "domain-name"; data = "house-ext.as205479.net"; } { name = "interface-mtu"; data = "1420"; }]; } { subnet = "192.168.10.0/24"; pools = [{ pool = "192.168.10.100 - 192.168.10.200"; }]; option-data = [{ name = "routers"; data = "192.168.10.1"; } { name = "domain-name-servers"; data = "192.168.10.1"; } { name = "domain-name"; data = "eduroam.as205479.net"; } { name = "interface-mtu"; data = "1420"; }]; }]; }; dhcp6.enable = true; dhcp6.settings = { interfaces-config.interfaces = ["br-internal" "vl-eduroam"]; lease-database = { type = "memfile"; persist = true; name = "/var/lib/kea/dhcp6.leases"; }; subnet6 = [{ subnet = "2a09:a443:1::/48"; pd-pools = [{ prefix = "2a09:a443:1:8000::"; prefix-len = 49; delegated-len = 64; }]; option-data = [{ name = "dns-servers"; data = "2a09:a443:1::1"; } { name = "domain-search"; data = "house.as205479.net"; }]; } { subnet = "2a09:a443:3::/48"; pd-pools = [{ prefix = "2a09:a443:3:8000::"; prefix-len = 49; delegated-len = 64; }]; option-data = [{ name = "dns-servers"; data = "2a09:a443:3::1"; } { name = "domain-search"; data = "eduroam.as205479.net"; }]; }]; }; }; })]; }