{ config, pkgs, lib, modulesPath, ... }: let coreAddress = "172.20.72.40"; corePrefixlen = 26; meshInterface = "bmx"; meshLoopback = "bmx_prime"; ddmeshRegisterUrl = "https://register.freifunk-dresden.de/bot.php"; secrets = import ; ddmeshRegisterKey = secrets.ddmeshRegisterKey; ddmeshNode = 51073; ddmeshAddrPart = "200.74"; rt_table = 7; bmxd = import ../../../lib/pkgs/bmxd.nix { inherit pkgs; }; sysinfo-json = import ./sysinfo-json.nix { inherit pkgs bmxd ddmeshNode; }; in { imports = [ (modulesPath + "/profiles/minimal.nix") ../../../lib ../../../lib/lxc-container.nix ../../../lib/shared.nix ]; boot.tmpOnTmpfs = true; c3d2 = { isInHq = false; enableHail = false; hq.statistics.enable = true; }; services.collectd.plugins.protocols = ""; networking.hostName = "freifunk"; networking.useNetworkd = true; networking.nameservers = [ "172.20.73.8" "9.9.9.9" ]; networking.firewall.enable = false; networking.nat = { enable = true; # This doesn't really work, hence the `extraCommands` externalInterface = meshInterface; #internalInterfaces = [ "core" ]; # Setup routing into Freifunk, # masquerading anything that isn't already their IP range extraCommands = '' ${pkgs.iproute}/bin/ip rule del priority 300 || true ${pkgs.iproute}/bin/ip rule add to 10.200.0.0/16 table bmx priority 300 ${pkgs.iptables}/bin/iptables -t nat -F POSTROUTING ${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING \ \! --source 10.200.0.0/15 -o ${meshInterface} -j SNAT --to 10.200.${ddmeshAddrPart} set -e ''; forwardPorts = [ { destination = "172.20.73.8"; proto = "udp"; sourcePort = 53; } { destination = "172.20.73.8"; proto = "tcp"; sourcePort = 53; } ]; }; # Configure rt_table name networking.iproute2 = { enable = true; rttablesExtraConfig = "${toString rt_table} bmx"; }; # Required for krops: ssh git services.openssh.enable = true; environment.systemPackages = with pkgs; [ git tcpdump ]; systemd.network = { netdevs = { # Dummy interface for primary (10.200) address bmx_prime = { enable = true; netdevConfig = { Kind = "bridge"; Name = meshLoopback; }; }; }; networks = { # Wired mesh interface "10-bmx" = { enable = true; matchConfig = { Name = meshInterface; }; addresses = [ { addressConfig = { Address = "10.201.${ddmeshAddrPart}/16"; Broadcast = "10.255.255.255"; }; } ]; }; # Dummy interface for primary (10.200) address "11-bmx-loopback" = { enable = true; matchConfig = { Name = meshLoopback; }; addresses = [ { addressConfig = { Address = "10.200.${ddmeshAddrPart}/32"; Broadcast = "10.255.255.255"; }; } ]; }; # ZW "20-core" = { enable = true; matchConfig = { Name = "core"; }; addresses = map (Address: { addressConfig = { inherit Address; }; }) [ "${coreAddress}/${toString corePrefixlen}" "2a02:8106:208:5281:8000::1/64" "fd23:42:c3d2:581:8000::1/64" ]; routes = map (Gateway: { routeConfig = { inherit Gateway; }; }) [ # upstream1 "2a02:8106:208:5281::b:0" # anon1 "172.20.72.7" ]; }; }; }; # Freifunk Dresden routing daemon systemd.services.bmxd = { after = [ "systemd-networkd.service" ]; wantedBy = [ "network.target" ]; serviceConfig = { ExecStart = '' ${bmxd}/sbin/bmxd \ --rt_table_offset=${toString rt_table} \ --no_fork 1 \ --throw-rules 0 \ --prio-rules 0 \ --gateway_tunnel_network 10.200.0.0/16 \ --purge_timeout 20 \ --one_way_tunnel 1 \ -g 500000/50000 \ dev=bmx_prime /linklayer 0 \ dev=${meshInterface} /linklayer 1 ''; Restart = "always"; }; }; # Re-register periodically systemd.services.ddmesh-register-node = { script = '' ${pkgs.curl}/bin/curl \ -o /tmp/ddmesh-registration.json \ '${ddmeshRegisterUrl}?registerkey=${ddmeshRegisterKey}&node=${toString ddmeshNode}' ''; serviceConfig = { User = "nobody"; Group = "nogroup"; }; }; systemd.timers.ddmesh-register-node = { partOf = [ "ddmesh-register-node.service" ]; wantedBy = [ "timers.target" ]; timerConfig.OnCalendar = "daily"; }; environment.etc."freifunk-server-version".text = "Custom NixOS configuration: 0.0.0"; # Refresh sysinfo.json systemd.services.sysinfo-json = { script = '' ${sysinfo-json}/bin/bmxddump.sh ${sysinfo-json}/bin/sysinfo-json.cgi > /tmp/sysinfo.json ''; }; systemd.timers.sysinfo-json = { partOf = [ "sysinfo-json.service" ]; wantedBy = [ "timers.target" ]; timerConfig.OnCalendar = "minutely"; }; # Advertise Freifunk routes to ZW core services.bird2 = { enable = true; config = '' protocol kernel K4 { ipv4 { export all; }; } protocol kernel K6 { ipv6 { export all; }; } protocol device { scan time 10; } protocol ospf v2 ZW4 { area 0 { networks { 172.20.72.0/21; }; stubnet 10.200.0.0/15; interface "core" { authentication cryptographic; password "${import }"; }; }; } protocol ospf v3 ZW6 { area 0 { networks { fd23:42:c3d2:500::/56; 2a02:8106:208:5200::/56; 2a02:8106:211:e900::/56; }; interface "core" { #authentication cryptographic; #password "${import }"; }; }; } router id ${coreAddress}; ''; }; # HTTP Reverse Proxy to provide services into Freifunk services.nginx = { enable = true; recommendedOptimisation = true; recommendedGzipSettings = true; appendHttpConfig = '' proxy_buffering off; ''; virtualHosts = { "c3d2.ffdd" = { default = true; root = ; locations = let sysinfo-json = { alias = "/tmp/sysinfo.json"; extraConfig = '' add_header Content-Type "application/json;charset=UTF-8"; ''; }; in { "/" = { index = "index.html"; extraConfig = '' etag off; add_header etag "\"${builtins.substring 11 32 ( + "/assets")}\""; ''; }; "=/sysinfo-json.cgi" = sysinfo-json; "=/sysinfo.json" = sysinfo-json; }; }; "storage.hq.c3d2.ffdd".locations."/".proxyPass = "http://storage.hq.c3d2.de/"; "grafana.hq.c3d2.ffdd".locations."/" = { proxyPass = "https://grafana.hq.c3d2.de/"; extraConfig = '' proxy_ssl_server_name on; ''; }; "influxdb.hq.c3d2.ffdd".locations."/".proxyPass = "http://grafana.hq.c3d2.de:8086/"; }; }; # This value determines the NixOS release with which your system is to be # compatible, in order to avoid breaking some software such as database # servers. You should change this only after NixOS release notes say you # should. system.stateVersion = "20.03"; # Did you read the comment? }