nix/nixos/router/default.nix
2023-11-13 09:11:22 -06:00

362 lines
8.7 KiB
Nix

{
flake,
inputs,
lib,
# outputs,
# config,
# 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";
lease = {
min = "192.168.0.5";
max = "192.168.0.250";
};
wan_if = "wan0";
lan_if = "lan0";
hosts = {
dragon = {
identifier = "dragon";
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
flake.diskoConfigurations.unencrypted
];
# TODO: perform a hardware scan
boot = {
loader = {
efi.canTouchEfiVariables = true;
systemd-boot.enable = true;
};
kernel = {
sysctl = {
"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;
};
};
};
powerManagement.cpuFreqGovernor = lib.mkDefault "ondemand";
services.fail2ban.enable = true;
services.radvd = {
enable = true;
# NOTE: this config is just the default arch linux config I think and may
# need tweaking? this is what I had on the arch linux router, though :shrug:
config = ''
interface lo
{
AdvSendAdvert on;
MinRtrAdvInterval 3;
MaxRtrAdvInterval 10;
AdvDefaultPreference low;
AdvHomeAgentFlag off;
prefix 2001:db8:1:0::/64
{
AdvOnLink on;
AdvAutonomous on;
AdvRouterAddr off;
};
prefix 0:0:0:1234::/64
{
AdvOnLink on;
AdvAutonomous on;
AdvRouterAddr off;
Base6to4Interface ppp0;
AdvPreferredLifetime 120;
AdvValidLifetime 300;
};
route 2001:db0:fff::/48
{
AdvRoutePreference high;
AdvRouteLifetime 3600;
};
RDNSS 2001:db8::1 2001:db8::2
{
AdvRDNSSLifetime 30;
};
DNSSL branch.example.com example.com
{
AdvDNSSLLifetime 30;
};
};
'';
};
services.resolved = {
enable = true;
extraConfig = ''
[Resolve]
DNSStubListener=no
'';
};
services.dnsmasq = {
enable = true;
settings = {
# server endpoints
listen-address = "::1,127.0.0.1,${ip}";
port = "53";
# DNS cache entries
cache-size = "10000";
# local domain entries
local = "/lan/";
domain = "lan";
expand-hosts = true;
dhcp-authoritative = true;
conf-file = "/usr/share/dnsmasq/trust-anchors.conf";
dnssec = true;
except-interface = "${wan_if}";
interface = "${lan_if}";
enable-ra = true;
# dhcp-option = "121,${cidr},${ip}";
dhcp-range = [
"lan,${lease.min},${lease.max},${netmask},10m"
"tag:${lan_if},::1,constructor:${lan_if},ra-names,12h"
];
dhcp-host = [
"${hosts.dragon.host},${hosts.dragon.ip},12h"
"${hosts.beefcake.host},${hosts.beefcake.ip},12h"
];
# 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"
];
server = [
"${ip}"
"8.8.8.8"
"8.8.4.4"
"1.1.1.1"
"1.0.0.1"
];
};
};
networking.extraHosts = ''
127.0.0.1 localhost
127.0.1.1 router.h.lyte.dev router
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
'';
networking.nat.enable = true; # TODO: maybe replace some of the nftables stuff with this?
networking.firewall.enable = false;
networking.nftables = {
enable = true;
flushRuleset = true;
tables = {
filter = {
family = "inet";
content = ''
chain input {
# type filter hook input priority filter; policy accept;
type filter hook input priority 0;
# anything from loopback interface
iifname "lo" accept
# accept traffic we originated
ct state { established, related } counter accept
ct state invalid counter drop
# 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
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 = {
enable = true;
extraConfig = ''
duid
# No way.... https://github.com/NetworkConfiguration/dhcpcd/issues/36#issuecomment-954777644
# issues caused by guests with oneplus devices
noarp
persistent
vendorclassid
option domain_name_servers, domain_name, domain_search
option classless_static_routes
option interface_mtu
option host_name
#option ntp_servers
require dhcp_server_identifier
slaac private
noipv4ll
noipv6rs
static domain_name_servers=${ip}
interface ${wan_if}
gateway
ipv6rs
iaid 1
# option rapid_commit
# ia_na 1
ia_pd 1 ${lan_if}
interface ${lan_if}
static ip_address=${cidr}
static routers=${ip}
static domain_name_servers=${ip}
'';
};
systemd.network = {
enable = true;
links = {
"${wan_if}" = {
enable = true;
matchConfig = {
MACAddress = "00:01:2e:82:73:59";
};
linkConfig = {
Name = wan_if;
};
};
"${lan_if}" = {
enable = true;
matchConfig = {
MACAddress = "00:01:2e:82:73:5a";
};
linkConfig = {
Name = lan_if;
};
};
};
};
services.avahi = {
enable = true;
reflector = true;
allowInterfaces = [
lan_if
];
};
system.stateVersion = "23.11";
}