{ hostName, wireguardPrivateKey }: { config, pkgs, ... }: let wan = "end0"; lan = "enp1s0"; bridge = "br-lan"; devices = "devices-vlan"; wifi = "wifi-vlan"; computer = "comptuer-vlan"; wg0 = "wg0"; in { sops.secrets.${wireguardPrivateKey} = { format = "binary"; sopsFile = ../../secrets/${wireguardPrivateKey}.bin; path = "/etc/wireguard-secret"; mode = "0400"; owner = "systemd-network"; group = "systemd-network"; restartUnits = [ "systemd-networkd.service" ]; }; boot.kernel = { sysctl = { "net.ipv6.conf.all.forwarding" = 1; "net.ipv6.conf.${bridge}.accept_ra" = 2; "net.ipv6.conf.${devices}.accept_ra" = 2; "net.ipv6.conf.${wifi}.accept_ra" = 2; "net.ipv6.conf.${computer}.accept_ra" = 2; "net.ipv4.conf.all.forwarding" = true; "net.ipv4.conf.default.rp_filter" = 1; "net.ipv4.conf.${wan}.rp_filter" = 1; "net.ipv4.conf.${bridge}.rp_filter" = 0; "net.ipv4.conf.${devices}.rp_filter" = 0; "net.ipv4.conf.${wifi}.rp_filter" = 0; "net.ipv4.conf.${computer}.rp_filter" = 0; }; }; environment.systemPackages = with pkgs; [ arp-scan wireguard-tools ]; systemd.network = { wait-online.anyInterface = true; netdevs = { "10-${devices}" = { netdevConfig = { Name = devices; Kind = "vlan"; }; vlanConfig.Id = 30; }; "10-${wifi}" = { netdevConfig = { Name = wifi; Kind = "vlan"; }; vlanConfig.Id = 40; }; "10-${computer}" = { netdevConfig = { Name = computer; Kind = "vlan"; }; vlanConfig.Id = 50; }; "20-${bridge}" = { netdevConfig = { Kind = "bridge"; Name = bridge; }; }; "30-${wg0}" = { netdevConfig = { Kind = "wireguard"; Name = wg0; MTUBytes = "1300"; }; wireguardConfig = { PrivateKeyFile = "/etc/wireguard-secret"; ListenPort = 51820; }; wireguardPeers = [ { # firestar PublicKey = "ppaJ0RAtdvFpdg0eJPkO0YnYnEMZhiwAlQJUHnC80EA="; AllowedIPs = [ "192.168.5.10" "2001:db8:5::10" ]; } { # graystripe PublicKey = "+7NZi6XmZdJGXLgUe6Ne4Xxh8hyR+kO1OIMf0U8g/HQ="; AllowedIPs = [ "192.168.5.11" "2001:db8:5::11" ]; } { # squirrelflight PublicKey = "utcnmBIFY5M6vXCeexiPkAHXwfv/8SQry0M30D3KYHc="; AllowedIPs = [ "192.168.5.12" "2001:db8:5::12" ]; } ]; }; }; networks = { "06-${wan}" = { matchConfig.Name = wan; linkConfig.RequiredForOnline = "routable"; networkConfig = { DHCP = true; IPv6AcceptRA = true; DNSOverTLS = true; DNSSEC = true; IPv6PrivacyExtensions = false; IPForward = true; LinkLocalAddressing = "ipv6"; }; }; "30-${lan}" = { matchConfig.Name = lan; linkConfig.RequiredForOnline = "enslaved"; networkConfig = { Bridge = bridge; ConfigureWithoutCarrier = true; VLAN = [ devices wifi computer ]; }; }; "40-${bridge}" = { matchConfig.Name = bridge; bridgeConfig = { }; address = [ "192.168.20.1/24" "2001:db8:20::1/64" ]; networkConfig = { IPv6SendRA = true; ConfigureWithoutCarrier = true; }; ipv6Prefixes = [{ Prefix = "2001:db8:20::/64"; }]; ipv6SendRAConfig = { EmitDNS = true; DNS = "2001:db8:20::1"; }; linkConfig.RequiredForOnline = "no"; }; "50-${devices}" = { matchConfig = { Name = devices; Type = "vlan"; }; address = [ "192.168.30.1/24" "2001:db8:30::1/64" ]; networkConfig = { IPv6SendRA = true; }; ipv6Prefixes = [{ Prefix = "2001:db8:30::/64"; }]; ipv6SendRAConfig = { EmitDNS = true; DNS = "2001:db8:30::1"; }; linkConfig.RequiredForOnline = "routable"; }; "50-${wifi}" = { matchConfig = { Name = wifi; Type = "vlan"; }; address = [ "192.168.40.1/24" "2001:db8:40::1/64" ]; networkConfig = { IPv6SendRA = true; }; ipv6Prefixes = [{ Prefix = "2001:db8:40::/64"; }]; ipv6SendRAConfig = { EmitDNS = true; DNS = "2001:db8:40::1"; }; linkConfig.RequiredForOnline = "routable"; }; "50-${computer}" = { matchConfig = { Name = computer; Type = "vlan"; }; address = [ "192.168.50.1/24" "2001:db8:50::1/64" ]; networkConfig = { IPv6SendRA = true; }; ipv6Prefixes = [{ Prefix = "2001:db8:50::/64"; }]; ipv6SendRAConfig = { EmitDNS = true; DNS = "2001:db8:50::1"; }; linkConfig.RequiredForOnline = "routable"; }; "60-${wg0}" = { matchConfig.Name = wg0; address = [ "192.168.5.1/24" "2001:db8:5::1/64" ]; networkConfig = { }; linkConfig.RequiredForOnline = "yes"; }; }; }; networking = { inherit hostName; useNetworkd = true; useDHCP = false; nat.enable = false; firewall.enable = false; nftables = { enable = true; checkRuleset = false; ruleset = '' define WAN=${wan} define LAN=${lan} define BRIDGE=${bridge} define DEVICES=${devices} define WIFI=${wifi} define COMPUTER=${computer} define WG0=${wg0} define HTTP_HOST=192.168.20.200 define HTTP_HOST_V6=2001:db8:20::200 define FORGEJO_HOST=192.168.20.201 define FORGEJO_HOST_V6=2001:db8:20::201 define FORGEJO_SSH_PORT=2222 define DRAWPILE_HOST=192.168.20.202 define DRAWPILE_HOST_V6=2001:db8:20::202 define DRAWPILE_TCP_PORT=27750 table inet filter { set internal_access_tcp { type inet_service; flags interval; elements = { 22, 3128 } } set network_required_udp { type inet_service; flags interval; elements = { 53, 67, 68, 546, 547 } } set firewall_out_tcp_accepted { type inet_service; flags interval; elements = { 22, 53, 80, 443, 853 } } set firewall_out_udp_accepted { type inet_service; flags interval; elements = { 53, 123, 67, 68, 546, 547 } } chain global { ct state { established, related } accept ct state invalid drop ip protocol icmp accept ip6 nexthdr icmpv6 accept } chain reject_politely { reject with icmp type port-unreachable } chain bridge_in { tcp dport { 80, 443 } ip daddr $HTTP_HOST ct state new accept comment "Allow HTTP/S to http host" tcp dport { 80, 443 } ip6 daddr $HTTP_HOST_V6 ct state new accept comment "Allow HTTP/S to http host" tcp dport $FORGEJO_SSH_PORT ip daddr $FORGEJO_HOST ct state new accept comment "Allow ssh to forgejo" tcp dport $FORGEJO_SSH_PORT ip6 daddr $FORGEJO_HOST_V6 ct state new accept comment "Allow ssh to forgejo" tcp dport $DRAWPILE_TCP_PORT ip daddr $DRAWPILE_HOST ct state new accept comment "Allow drawpile traffic to drawpile" tcp dport $DRAWPILE_TCP_PORT ip6 daddr $DRAWPILE_HOST_V6 ct state new accept comment "Allow drawpile traffic to drawpile" } chain bridge_out { accept } chain devices_in {} chain devices_out { udp dport 123 ct state new accept comment "Allow NTP from devices network" tcp dport { 80, 443 } ct state new accept comment "Allow HTTP/S from devices network" } chain wifi_in {} chain wifi_out { accept } chain computer_in {} chain computer_out { accept } chain wg_in {} chain wg_out { accept } chain rate_limit { flow table rate-limit-ftable { ip saddr limit rate 2/minute } accept comment "Allow rate limited" } chain forward { type filter hook forward priority filter; policy drop; jump global oifname vmap { $BRIDGE : jump bridge_in, $DEVICES : jump devices_in, $WIFI : jump wifi_in, $COMPUTER : jump computer_in, $WG0 : jump wg_in } oifname $WAN iifname vmap { $BRIDGE : jump bridge_out, $DEVICES : jump devices_out, $WIFI : jump wifi_out, $COMPUTER : jump computer_out, $WG0 : jump wg_out } iifname $WG0 oifname $BRIDGE ct state new accept comment "Allow from wireguard to bridge" iifname $BRIDGE oifname $WG0 ct state new accept comment "Allow from bridge to wireguard" jump reject_politely } chain input { type filter hook input priority 0; policy drop; jump global iifname lo accept tcp dport @internal_access_tcp ct state new iifname vmap { $BRIDGE : accept, $WG0 : accept, $COMPUTER : accept, $DEVICES : jump reject_politely, $WIFI : jump rate_limit, $WAN : jump rate_limit } udp dport 51820 ct state new accept comment "Allow wireguard" udp dport @network_required_udp ct state new accept comment "Allow internal network required stuff" jump reject_politely } chain output { type filter hook output priority 100; policy drop; jump global tcp dport @firewall_out_tcp_accepted ct state new accept udp dport @firewall_out_udp_accepted ct state new accept jump reject_politely } } table ip nat { chain prerouting { type nat hook prerouting priority -100; policy accept; fib daddr type local tcp dport { 80, 443 } dnat to $HTTP_HOST fib daddr type local tcp dport 22 dnat to $FORGEJO_HOST:$FORGEJO_SSH_PORT fib daddr type local tcp dport $DRAWPILE_TCP_PORT dnat to $DRAWPILE_HOST } chain postrouting { type nat hook postrouting priority 100; policy accept; oifname $WAN masquerade iifname $BRIDGE oifname $BRIDGE ip daddr $HTTP_HOST tcp dport { 80, 443 } masquerade iifname $BRIDGE oifname $BRIDGE ip daddr $FORGEJO_HOST tcp dport $FORGEJO_SSH_PORT masquerade iifname $BRIDGE oifname $BRIDGE ip daddr $DRAWPILE_HOST tcp dport $DRAWPILE_TCP_PORT masquerade } } table ip6 nat { chain prerouting { type nat hook prerouting priority -100; policy accept; fib daddr type local tcp dport { 80, 443 } dnat to $HTTP_HOST_V6 fib daddr type local tcp dport 22 dnat to $FORGEJO_HOST_V6:$FORGEJO_SSH_PORT fib daddr type local tcp dport $DRAWPILE_TCP_PORT dnat to $DRAWPILE_HOST_V6 } chain postrouting { type nat hook postrouting priority 100; policy accept; oifname $WAN masquerade iifname $BRIDGE oifname $BRIDGE ip6 daddr $HTTP_HOST_V6 tcp dport { 80, 443 } masquerade iifname $BRIDGE oifname $BRIDGE ip6 daddr $FORGEJO_HOST_V6 tcp dport $FORGEJO_SSH_PORT masquerade iifname $BRIDGE oifname $BRIDGE ip6 daddr $DRAWPILE_HOST_V6 tcp dport $DRAWPILE_TCP_PORT masquerade } } ''; }; }; services.openssh.ports = [ 22 3128 ]; services.resolved.enable = false; services.dnsmasq = { enable = true; settings = { server = [ # OpenDNS "208.67.222.222" "208.67.220.220" "2620:119:53::35" "2620:119:53::53" # Quad9 "9.9.9.11" "149.112.112.11" "2620:fe::11" "2620:fe::fe:11" # Cloudflare "1.1.1.1" "1.0.0.1" "2606:4700:4700::1111" "2606:4700:4700::1001" ]; domain-needed = true; bogus-priv = true; no-resolv = true; # dhcpv6 stuff enable-ra = true; dhcp-authoritative = true; strict-order = true; cache-size = 1000; dhcp-range = [ # format TAG,START,END,?MASK,?options,LEASE "${bridge},192.168.20.50,192.168.20.90,24h" "${bridge},::ffff,constructor:${bridge},ra-names,64,24h" "${devices},192.168.30.10,192.168.30.240,24h" "${devices},::10,constructor:${devices},ra-names,64,24h" "${wifi},192.168.40.10,192.168.40.240,24h" "${wifi},::10,constructor:${wifi},ra-names,64,24h" "${computer},192.168.50.10,192.168.50.240,24h" "${computer},::10,constructor:${computer},ra-names,64,24h" ]; interface = [ bridge devices wifi computer wg0 ]; dhcp-option = [ "${bridge},option:router,192.168.20.1" "${bridge},option:dns-server,192.168.20.1" "${bridge},option6:dns-server,2001:db8:20::1" "${devices},option:router,192.168.30.1" "${devices},option:dns-server,192.168.30.1" "${devices},option6:dns-server,2001:db8:30::1" "${wifi},option:router,192.168.40.1" "${wifi},option:dns-server,192.168.40.1" "${wifi},option6:dns-server,2001:db8:40::1" "${computer},option:router,192.168.50.1" "${computer},option:dns-server,192.168.50.1" "${computer},option6:dns-server,2001:db8:50::1" ]; local = "/lan/"; domain = "lan"; expand-hosts = true; no-hosts = true; address = [ "/router.lan/192.168.20.1" "/router.lan/2001:db8:20::1" ]; }; }; services.irqbalance.enable = false; }