From c3bc8fc684a8787cdacca7e37a7caebda1a75ec6 Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Thu, 2 Nov 2023 20:27:53 -0500 Subject: [PATCH] I think the router config is ready Nothing to do but install it and see what breaks --- nixos/router/default.nix | 222 +++++++++++++++++++++++++++------------ 1 file changed, 152 insertions(+), 70 deletions(-) diff --git a/nixos/router/default.nix b/nixos/router/default.nix index 794d0c3..2007246 100644 --- a/nixos/router/default.nix +++ b/nixos/router/default.nix @@ -4,9 +4,11 @@ lib, # outputs, # config, - pkgs, + # pkgs, ... }: let + # NOTE: I could turn this into a cool NixOS module? + # TODO: review https://francis.begyn.be/blog/nixos-home-router ip = "192.168.0.1"; cidr = "${ip}/16"; netmask = "255.255.0.0"; @@ -22,10 +24,16 @@ host = "dragon"; ip = "192.168.0.10"; }; + beefcake = { + identifier = "beefcake"; + host = "beefcake"; + ip = "192.168.0.9"; + }; }; in { networking.hostName = "router"; networking.domain = "h.lyte.dev"; + networking.useDHCP = false; imports = [ inputs.disko.nixosModules.disko @@ -41,9 +49,15 @@ in { }; kernel = { sysctl = { - "net.ipv4.ip_forward" = 1; - "net.ipv6.conf.all.forwarding" = 1; + "net.ipv4.conf.all.forwarding" = true; + "net.ipv6.conf.all.forwarding" = true; + + "net.ipv6.conf.all.accept_ra" = 0; + "net.ipv6.conf.all.autoconf" = 0; + "net.ipv6.conf.all.use_tempaddr" = 0; + "net.ipv6.conf.wan0.accept_ra" = 2; + # "net.ipv6.conf.wan0.autoconf" = 1; }; }; }; @@ -110,61 +124,59 @@ in { services.dnsmasq = { enable = true; - # TODO: port to settings - extraConfig = '' + settings = { # server endpoints - listen-address=::1,127.0.0.1,${ip} - port=53 + listen-address = "::1,127.0.0.1,${ip}"; + port = "53"; # DNS cache entries - cache-size=10000 + cache-size = "10000"; # local domain entries - local=/lan/ - domain=lan - expand-hosts + local = "/lan/"; + domain = "lan"; + expand-hosts = true; - dhcp-authoritative + dhcp-authoritative = true; - conf-file=/usr/share/dnsmasq/trust-anchors.conf - dnssec + conf-file = "/usr/share/dnsmasq/trust-anchors.conf"; + dnssec = true; - except-interface=${wan_if} - interface=${lan_if} + except-interface = "${wan_if}"; + interface = "${lan_if}"; - enable-ra + enable-ra = true; - # dhcp-option=121,${cidr},${ip} + # dhcp-option = "121,${cidr},${ip}"; - dhcp-range=lan,${lease.min},${lease.max},${netmask},10m - dhcp-range=tag:${lan_if},::1,constructor:${lan_if},ra-names,12h + dhcp-range = [ + "lan,${lease.min},${lease.max},${netmask},10m" + "tag:${lan_if},::1,constructor:${lan_if},ra-names,12h" + ]; - dhcp-host=${hosts.dragon.identifier},${hosts.dragon.ip},12h + dhcp-host = [ + "${hosts.dragon.host},${hosts.dragon.ip},12h" + "${hosts.beefcake.host},${hosts.beefcake.ip},12h" + ]; - # TODO: parameterize the rest? + # may need to go in /etc/hosts (networking.extraHosts), too? + address = [ + "/video.lyte.dev/192.168.0.9" + "/git.lyte.dev/192.168.0.9" + "/bw.lyte.dev/192.168.0.9" + "/files.lyte.dev/192.168.0.9" + "/vpn.h.lyte.dev/192.168.0.9" + "/.h.lyte.dev/192.168.0.9" + ]; - dhcp-host=beefcake,192.168.0.9,12h - dhcp-host=chromebox,192.168.0.5,12h - dhcp-host=B-C02G56VXML85,192.168.0.128,12h - dhcp-host=B-W4KNHWJ6XY,192.168.0.217,12h - dhcp-host=mnemonic,192.168.0.248,ea:1b:7a:fb:8b:b8,12h - # dhcp-host=frontdoorcam,192.168.0.89,9c:8e:cd:2b:71:e9,120m - dhcp-host=AMC058BA_A75F1E,192.168.0.150,12h - dhcp-host=AMC0587F_A2969A,192.168.0.151,12h - - address=/video.lyte.dev/192.168.0.9 - address=/git.lyte.dev/192.168.0.9 - address=/bw.lyte.dev/192.168.0.9 - address=/files.lyte.dev/192.168.0.9 - address=/vpn.h.lyte.dev/192.168.0.9 - address=/.h.lyte.dev/192.168.0.9 - - server=${ip} - server=8.8.8.8 - server=8.8.4.4 - server=1.1.1.1 - server=1.0.0.1 - ''; + server = [ + "${ip}" + "8.8.8.8" + "8.8.4.4" + "1.1.1.1" + "1.0.0.1" + ]; + }; }; networking.extraHosts = '' @@ -175,42 +187,104 @@ in { ff02::1 ip6-allnodes ff02::2 ip6-allrouters - 192.168.0.9 git.lyte.dev - 192.168.0.9 video.lyte.dev - 192.168.0.9 files.lyte.dev - 192.168.0.9 bw.lyte.dev - 192.168.0.9 vpn.h.lyte.dev ''; + networking.nat.enable = true; + networking.firewall.enable = false; networking.nftables = { enable = true; flushRuleset = true; - }; - networking.firewall = { - # TODO: allow users to ssh to git.lyte.dev - # TODO: allow remote backuppers to ssh to beefcake - # TODO: allow DNS internally - # TODO: allow 67 for DHCP - # TODO: allow 2201 for router ssh access? - # TODO: allow 25565 to bald for minecraft - # TODO: allow all icmp stuff and dhcp stuff (including dhcpv6-client) + tables = { + filter = { + family = "inet"; + content = '' + chain input { + # type filter hook input priority filter; policy accept; + type filter hook input priority 0; - # filterForward = true; + # anything from loopback interface + iifname "lo" accept - extraInputRules = '' - ''; - extraForwardRules = '' - ''; + # accept traffic we originated + ct state { established, related } counter accept + ct state invalid counter drop - enable = true; + # ICMP + ip6 nexthdr icmpv6 icmpv6 type { echo-request, nd-neighbor-solicit, nd-neighbor-advert, nd-router-solicit, nd-router-advert, mld-listener-query, destination-unreachable, packet-too-big, time-exceeded, parameter-problem } counter accept + ip protocol icmp icmp type { echo-request, destination-unreachable, router-advertisement, time-exceeded, parameter-problem } counter accept + ip protocol icmpv6 counter accept + ip protocol icmp counter accept + meta l4proto ipv6-icmp counter accept - package = pkgs.nftables; - allowPing = true; - allowedTCPPorts = [22]; - allowedUDPPorts = []; - # allowedTCPPortRanges = [{from = 1; to = 10;}]; - # allowedUDPPortRanges = [{from = 1; to = 10;}]; + udp dport dhcpv6-client counter accept + + tcp dport { 64022, 22, 53, 67, 25565 } counter accept + udp dport { 64020, 22, 53, 67 } counter accept + + # iifname "iot" ip saddr $iot-ip tcp dport { llmnr } counter accept + # iifname "iot" ip saddr $iot-ip udp dport { mdns, llmnr } counter accept + iifname "${lan_if}" tcp dport { llmnr } counter accept + iifname "${lan_if}" udp dport { mdns, llmnr } counter accept + + counter drop + } + + # allow all outgoing + chain output { + type filter hook output priority 0; + accept + } + + chain forward { + type filter hook forward priority 0; + accept + } + ''; + }; + + nat = { + family = "ip"; + content = '' + set masq_saddr { + type ipv4_addr + flags interval + elements = { ${cidr} } + } + + map map_port_ipport { + type inet_proto . inet_service : ipv4_addr . inet_service + } + + chain prerouting { + iifname ${lan_if} accept + + type nat hook prerouting priority dstnat + 1; policy accept; + fib daddr type local dnat ip addr . port to meta l4proto . th dport map @map_port_ipport + + iifname ${wan_if} tcp dport { 22, 80, 443, 25565, 64022 } dnat to ${hosts.beefcake.ip} + iifname ${wan_if} udp dport { 64020 } dnat to ${hosts.beefcake.ip} + + # iifname ${wan_if} tcp dport { 25565 } dnat to 192.168.0.244 + # iifname ${wan_if} udp dport { 25565 } dnat to 192.168.0.244 + + # router + iifname ${wan_if} tcp dport { 2201 } dnat to ${ip} + } + + chain output { + type nat hook output priority -99; policy accept; + ip daddr != 127.0.0.0/8 oif "lo" dnat ip addr . port to meta l4proto . th dport map @map_port_ipport + } + + chain postrouting { + type nat hook postrouting priority srcnat + 1; policy accept; + oifname ${lan_if} masquerade + ip saddr @masq_saddr masquerade + } + ''; + }; + }; }; networking.dhcpcd = { @@ -276,5 +350,13 @@ in { }; }; + services.avahi = { + enable = true; + reflector = true; + interfaces = [ + lan_if + ]; + }; + system.stateVersion = "23.11"; }