{ config, lib, pkgs, ... }: with lib; let cfg = config.orbekk.router; devices = ["eno1" "eno2"]; router-netns-up = pkgs.writeScript "router-netns-up" '' #!${pkgs.bash}/bin/bash ip netns add router ip netns exec router ip link set lo up ${lib.concatMapStrings (device: '' ip link set ${device} netns router '') devices} ip link add router-vport type veth peer name dragon-vport netns router ''; router-netns-down = pkgs.writeScript "router-netns-down" '' #!${pkgs.bash}/bin/bash ip link del main ip netns del router ''; router-config = { config, lib, pkgs, ... }: { system.stateVersion = "22.05"; virtualisation.vswitch.enable = true; virtualisation.vswitch.resetOnStart = true; networking.vswitches.kjlan = { interfaces.wan-vport = { vlan = 10; type = "internal"; }; interfaces.lan-vport = { vlan = 100; type = "internal"; }; interfaces.admin-vport = { vlan = 255; type = "internal"; }; interfaces.dragon-vport = { vlan = 100; }; extraOvsctlCmds = '' add-bond kjlan bond0 eno1 eno2 lacp=active set interface wan-vport mac=\"3c:97:0e:19:7e:5c\" ''; }; networking.interfaces.eno1 = {}; networking.interfaces.eno2 = {}; networking.interfaces.wan-vport = { useDHCP = true; }; networking.interfaces.lan-vport = { ipv4.addresses = [{address = "172.20.100.1"; prefixLength = 24;}]; }; networking.interfaces.admin-vport = { ipv4.addresses = [{address = "10.10.255.18"; prefixLength = 24;}]; ipv4.routes = [{address = "10.10.255.0"; prefixLength = 24;}]; }; services.dnsmasq = { enable = true; servers = [ "1.1.1.1" "8.8.8.8" "8.8.4.4" ]; resolveLocalQueries = false; extraConfig = '' no-resolv no-hosts dhcp-authoritative enable-ra address=/localhost/::1 address=/localhost/127.0.0.1 dhcp-range=lan,172.20.100.10,172.20.100.254,5m dhcp-option=net:lan,option:router,172.20.100.1 dhcp-option=net:lan,option:dns-server,172.20.100.1 ''; }; networking.dhcpcd = { enable = true; extraConfig = '' noipv6rs noipv6 nohook resolv.conf interface wan-vport dhcp ''; }; networking.firewall.enable = false; networking.nftables.enable = true; networking.nftables.ruleset = let ports-to-csv = ports: concatStringsSep "," (map toString ports); in '' table inet filter { chain input { type filter hook input priority 0; iif lo accept; ct state {established, related} accept; counter drop; } chain output { type filter hook output priority 0 counter accept } chain forward { type filter hook forward priority 0; policy drop; ct state vmap { established : accept, related : accept, invalid : drop }; counter drop; } } table nat postrouting { chain nat { type nat hook postrouting priority 100; ip saddr 172.16.0.0/12 oif {"wan-vport"} masquerade; } } ''; }; in { options = { orbekk.router = { enable = mkEnableOption "Enable router config"; }; }; config = mkIf cfg.enable { boot.kernel.sysctl = { "net.ipv4.conf.all.forwarding" = true; "net.ipv4.conf.default.forwarding" = true; "net.ipv6.conf.all.forwarding" = true; "net.ipv6.conf.default.forwarding" = true; }; systemd.services."router-netns" = { description = "router network namespace"; before = ["network.target"]; after = ["network-interfaces.target"]; path = with pkgs; [bash iproute]; serviceConfig = { Type = "oneshot"; RemainAfterExit = "yes"; ExecStart = "${router-netns-up}"; ExecStop = "${router-netns-down}"; }; }; networking.wireguard.interfaces.mullvad.interfaceNamespace = "router"; systemd.services."container@router" = { after = ["router-netns.service"]; requires = ["router-netns.service"]; wantedBy = ["network.target"]; }; containers.router = { autoStart = true; extraFlags = ["--network-namespace-path" "/var/run/netns/router"]; privateNetwork = false; config = router-config; additionalCapabilities = ["CAP_NET_ADMIN"]; }; }; }