2023-11-26 01:29:44 +00:00
|
|
|
index: { lib, allAssignments, ... }:
|
2023-11-18 22:54:43 +00:00
|
|
|
let
|
2023-11-19 22:05:24 +00:00
|
|
|
inherit (builtins) elemAt;
|
2023-12-03 22:58:28 +00:00
|
|
|
inherit (lib.my) net mkVLAN;
|
2023-11-19 22:05:24 +00:00
|
|
|
inherit (lib.my.c) pubDomain;
|
2023-12-16 15:59:33 +00:00
|
|
|
inherit (lib.my.c.home) domain vlans prefixes vips routers routersPubV4;
|
2023-11-19 22:05:24 +00:00
|
|
|
|
|
|
|
name = elemAt routers index;
|
2023-12-16 13:00:10 +00:00
|
|
|
otherIndex = 1 - index;
|
2023-11-18 22:54:43 +00:00
|
|
|
in
|
|
|
|
{
|
|
|
|
nixos.systems."${name}" = {
|
|
|
|
assignments = {
|
|
|
|
modem = {
|
2023-11-19 22:05:24 +00:00
|
|
|
ipv4 = {
|
|
|
|
address = net.cidr.host (254 - index) prefixes.modem.v4;
|
|
|
|
gateway = null;
|
|
|
|
};
|
2023-11-18 22:54:43 +00:00
|
|
|
};
|
|
|
|
core = {
|
|
|
|
name = "${name}-core";
|
|
|
|
inherit domain;
|
2023-12-16 15:59:33 +00:00
|
|
|
mtu = 1500;
|
2023-11-18 22:54:43 +00:00
|
|
|
ipv4 = {
|
|
|
|
address = net.cidr.host (index + 1) prefixes.core.v4;
|
2023-11-19 22:05:24 +00:00
|
|
|
gateway = null;
|
2023-11-18 22:54:43 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
hi = {
|
2023-11-25 15:07:58 +00:00
|
|
|
name = "${name}-hi";
|
2023-12-16 15:59:33 +00:00
|
|
|
inherit domain;
|
|
|
|
mtu = 9000;
|
2023-11-18 22:54:43 +00:00
|
|
|
ipv4 = {
|
|
|
|
address = net.cidr.host (index + 1) prefixes.hi.v4;
|
|
|
|
mask = 22;
|
|
|
|
gateway = null;
|
|
|
|
};
|
|
|
|
ipv6.address = net.cidr.host (index + 1) prefixes.hi.v6;
|
|
|
|
};
|
|
|
|
lo = {
|
|
|
|
name = "${name}-lo";
|
|
|
|
inherit domain;
|
2023-12-16 15:59:33 +00:00
|
|
|
mtu = 1500;
|
2023-11-18 22:54:43 +00:00
|
|
|
ipv4 = {
|
|
|
|
address = net.cidr.host (index + 1) prefixes.lo.v4;
|
|
|
|
mask = 21;
|
|
|
|
gateway = null;
|
|
|
|
};
|
|
|
|
ipv6.address = net.cidr.host (index + 1) prefixes.lo.v6;
|
|
|
|
};
|
|
|
|
untrusted = {
|
|
|
|
name = "${name}-ut";
|
|
|
|
inherit domain;
|
2023-12-16 15:59:33 +00:00
|
|
|
mtu = 1500;
|
2023-11-18 22:54:43 +00:00
|
|
|
ipv4 = {
|
|
|
|
address = net.cidr.host (index + 1) prefixes.untrusted.v4;
|
|
|
|
mask = 24;
|
|
|
|
gateway = null;
|
|
|
|
};
|
|
|
|
ipv6.address = net.cidr.host (index + 1) prefixes.untrusted.v6;
|
|
|
|
};
|
2023-11-26 01:29:44 +00:00
|
|
|
as211024 = {
|
|
|
|
ipv4 = {
|
|
|
|
address = net.cidr.host (index + 2) prefixes.as211024.v4;
|
|
|
|
gateway = null;
|
|
|
|
};
|
2023-12-03 22:58:28 +00:00
|
|
|
ipv6 = {
|
|
|
|
address = net.cidr.host ((1*65536*65536*65536) + index + 1) prefixes.as211024.v6;
|
2023-12-20 01:30:27 +00:00
|
|
|
gateway = net.cidr.host ((2*65536*65536*65536) + 1) prefixes.as211024.v6;
|
2023-12-03 22:58:28 +00:00
|
|
|
};
|
2023-11-26 01:29:44 +00:00
|
|
|
};
|
2023-11-18 22:54:43 +00:00
|
|
|
};
|
|
|
|
|
2023-12-16 15:59:33 +00:00
|
|
|
extraAssignments = {
|
|
|
|
router-hi.hi = {
|
|
|
|
name = "router-hi";
|
|
|
|
inherit domain;
|
|
|
|
ipv4 = {
|
|
|
|
address = vips.hi.v4;
|
|
|
|
mask = 22;
|
|
|
|
};
|
|
|
|
ipv6.address = vips.hi.v6;
|
|
|
|
};
|
|
|
|
router-lo.lo = {
|
|
|
|
name = "router-lo";
|
|
|
|
inherit domain;
|
|
|
|
ipv4 = {
|
|
|
|
address = vips.lo.v4;
|
|
|
|
mask = 21;
|
|
|
|
};
|
|
|
|
ipv6.address = vips.lo.v6;
|
|
|
|
};
|
|
|
|
router-ut.untrusted = {
|
|
|
|
name = "router-ut";
|
|
|
|
inherit domain;
|
|
|
|
ipv4.address = vips.untrusted.v4;
|
|
|
|
ipv6.address = vips.untrusted.v6;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2023-11-18 22:54:43 +00:00
|
|
|
configuration = { lib, pkgs, config, assignments, allAssignments, ... }:
|
|
|
|
let
|
|
|
|
inherit (lib) mkIf mkMerge mkForce;
|
|
|
|
inherit (lib.my) networkdAssignment;
|
2023-12-11 01:55:02 +00:00
|
|
|
inherit (lib.my.c) networkd;
|
2023-11-18 22:54:43 +00:00
|
|
|
in
|
|
|
|
{
|
2023-11-21 11:18:17 +00:00
|
|
|
imports = map (m: import m index) [
|
2023-11-25 17:18:34 +00:00
|
|
|
./keepalived.nix
|
2023-11-21 11:18:17 +00:00
|
|
|
./dns.nix
|
2023-12-16 15:59:33 +00:00
|
|
|
./radvd.nix
|
2023-12-16 18:50:51 +00:00
|
|
|
./kea.nix
|
2023-11-21 11:18:17 +00:00
|
|
|
];
|
2023-11-19 14:32:23 +00:00
|
|
|
|
2023-11-18 22:54:43 +00:00
|
|
|
config = {
|
|
|
|
environment = {
|
2023-11-21 11:18:17 +00:00
|
|
|
systemPackages = with pkgs; [
|
|
|
|
ethtool
|
2023-11-26 01:29:44 +00:00
|
|
|
conntrack-tools
|
2023-11-18 22:54:43 +00:00
|
|
|
];
|
|
|
|
};
|
|
|
|
|
|
|
|
services = {
|
|
|
|
resolved = {
|
|
|
|
llmnr = "false";
|
|
|
|
extraConfig = ''
|
|
|
|
MulticastDNS=false
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
iperf3 = {
|
|
|
|
enable = true;
|
|
|
|
openFirewall = true;
|
|
|
|
};
|
2023-11-20 01:51:46 +00:00
|
|
|
|
2023-11-25 16:28:43 +00:00
|
|
|
networkd-dispatcher = {
|
|
|
|
enable = true;
|
|
|
|
rules = {
|
|
|
|
# tc filter hasn't been networkd-ified yet
|
|
|
|
setup-wan-mirror = {
|
|
|
|
onState = [ "configured" ];
|
|
|
|
script = ''
|
|
|
|
#!${pkgs.runtimeShell}
|
2023-12-11 01:55:02 +00:00
|
|
|
if [ $IFACE = "wan-ifb" ]; then
|
|
|
|
${pkgs.iproute2}/bin/tc filter add dev wan parent ffff: matchall action mirred egress redirect dev $IFACE
|
2023-11-25 16:28:43 +00:00
|
|
|
fi
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
2024-06-24 00:08:55 +01:00
|
|
|
|
|
|
|
nginx.enable = true;
|
2023-11-18 22:54:43 +00:00
|
|
|
};
|
|
|
|
|
2024-06-24 00:08:55 +01:00
|
|
|
networking = { inherit domain; };
|
2023-11-19 22:05:24 +00:00
|
|
|
|
2024-03-13 21:52:09 +00:00
|
|
|
systemd.services =
|
|
|
|
let
|
|
|
|
waitOnline = "systemd-networkd-wait-online@wan.service";
|
|
|
|
in
|
|
|
|
{
|
|
|
|
ipsec = {
|
2023-11-26 01:29:44 +00:00
|
|
|
after = [ waitOnline ];
|
|
|
|
requires = [ waitOnline ];
|
|
|
|
};
|
2024-03-13 21:52:09 +00:00
|
|
|
|
|
|
|
ipv6-clear-default-route = {
|
|
|
|
description = "Clear IPv6 RA default route";
|
|
|
|
after = [ waitOnline ];
|
|
|
|
requires = [ waitOnline ];
|
|
|
|
script = ''
|
|
|
|
# Seems like we can sometimes pick up a default route somehow...
|
|
|
|
${pkgs.iproute2}/bin/ip -6 route del default via fe80::1 || true
|
|
|
|
'';
|
|
|
|
serviceConfig.Type = "oneshot";
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
};
|
2023-11-26 01:29:44 +00:00
|
|
|
};
|
|
|
|
|
2023-11-18 22:54:43 +00:00
|
|
|
systemd.network = {
|
|
|
|
wait-online.enable = false;
|
|
|
|
config = {
|
|
|
|
networkConfig = {
|
|
|
|
ManageForeignRoutes = false;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2023-12-03 22:58:28 +00:00
|
|
|
netdevs = mkMerge [
|
2023-11-18 22:54:43 +00:00
|
|
|
{
|
2023-12-11 01:55:02 +00:00
|
|
|
"25-wan-ifb".netdevConfig = {
|
|
|
|
Name = "wan-ifb";
|
2023-11-25 16:28:43 +00:00
|
|
|
Kind = "ifb";
|
|
|
|
};
|
2023-11-21 09:54:09 +00:00
|
|
|
"30-lan-core".netdevConfig = {
|
|
|
|
Name = "lan-core";
|
|
|
|
Kind = "macvlan";
|
|
|
|
MTUBytes = "1500";
|
|
|
|
};
|
2023-11-18 22:54:43 +00:00
|
|
|
}
|
|
|
|
|
2023-11-19 22:05:24 +00:00
|
|
|
(mkVLAN "lan-hi" vlans.hi)
|
|
|
|
(mkVLAN "lan-lo" vlans.lo)
|
|
|
|
(mkVLAN "lan-untrusted" vlans.untrusted)
|
2023-11-18 22:54:43 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
networks =
|
|
|
|
let
|
2023-12-16 15:59:33 +00:00
|
|
|
mkVLANConfig = name:
|
2023-11-19 22:05:24 +00:00
|
|
|
let
|
|
|
|
iface = "lan-${name}";
|
|
|
|
in
|
|
|
|
{
|
|
|
|
"60-${iface}" = mkMerge [
|
|
|
|
(networkdAssignment iface assignments."${name}")
|
2023-11-18 22:54:43 +00:00
|
|
|
{
|
2023-12-16 15:59:33 +00:00
|
|
|
dns = [ "127.0.0.1" "::1" ];
|
2023-11-18 22:54:43 +00:00
|
|
|
domains = [ config.networking.domain ];
|
2023-12-16 15:59:33 +00:00
|
|
|
networkConfig.IPv6AcceptRA = mkForce false;
|
2023-11-18 22:54:43 +00:00
|
|
|
}
|
|
|
|
];
|
|
|
|
};
|
|
|
|
in
|
|
|
|
mkMerge [
|
|
|
|
{
|
2023-12-11 01:55:02 +00:00
|
|
|
"50-wan-ifb" = {
|
|
|
|
matchConfig.Name = "wan-ifb";
|
|
|
|
networkConfig = networkd.noL3;
|
2023-11-25 16:28:43 +00:00
|
|
|
extraConfig = ''
|
|
|
|
[CAKE]
|
2024-10-19 21:18:21 +01:00
|
|
|
Bandwidth=490M
|
2024-03-21 20:41:28 +00:00
|
|
|
RTTSec=50ms
|
2023-11-25 16:28:43 +00:00
|
|
|
PriorityQueueingPreset=besteffort
|
|
|
|
# DOCSIS preset
|
|
|
|
OverheadBytes=18
|
|
|
|
MPUBytes=64
|
|
|
|
CompensationMode=none
|
|
|
|
'';
|
|
|
|
};
|
2023-11-18 22:54:43 +00:00
|
|
|
"50-wan" = mkMerge [
|
|
|
|
(networkdAssignment "wan" assignments.modem)
|
|
|
|
{
|
|
|
|
matchConfig.Name = "wan";
|
|
|
|
DHCP = "ipv4";
|
2023-11-19 22:05:24 +00:00
|
|
|
dns = [ "127.0.0.1" "::1" ];
|
2023-11-18 22:54:43 +00:00
|
|
|
dhcpV4Config.UseDNS = false;
|
2023-12-11 01:55:02 +00:00
|
|
|
|
|
|
|
qdiscConfig = {
|
|
|
|
Parent = "ingress";
|
|
|
|
Handle = "0xffff";
|
|
|
|
};
|
|
|
|
extraConfig = ''
|
|
|
|
[CAKE]
|
|
|
|
Parent=root
|
2024-10-19 21:18:21 +01:00
|
|
|
Bandwidth=48M
|
2024-03-21 20:41:28 +00:00
|
|
|
RTTSec=50ms
|
2023-12-11 01:55:02 +00:00
|
|
|
'';
|
2023-11-18 22:54:43 +00:00
|
|
|
}
|
|
|
|
];
|
|
|
|
|
2023-11-21 09:54:09 +00:00
|
|
|
"55-lan" = {
|
|
|
|
matchConfig.Name = "lan";
|
|
|
|
vlan = [ "lan-hi" "lan-lo" "lan-untrusted" "wan-tunnel" ];
|
|
|
|
macvlan = [ "lan-core" ];
|
2023-12-11 01:55:02 +00:00
|
|
|
networkConfig = networkd.noL3;
|
2023-11-21 09:54:09 +00:00
|
|
|
};
|
|
|
|
"60-lan-core" = mkMerge [
|
|
|
|
(networkdAssignment "lan-core" assignments.core)
|
2023-11-19 22:05:24 +00:00
|
|
|
{
|
2023-11-21 09:54:09 +00:00
|
|
|
matchConfig.Name = "lan-core";
|
2023-11-19 22:05:24 +00:00
|
|
|
networkConfig.IPv6AcceptRA = mkForce false;
|
|
|
|
}
|
|
|
|
];
|
2023-11-26 01:29:44 +00:00
|
|
|
|
|
|
|
"90-l2mesh-as211024" = mkMerge [
|
|
|
|
(networkdAssignment "as211024" assignments.as211024)
|
|
|
|
{
|
|
|
|
matchConfig.Name = "as211024";
|
|
|
|
networkConfig.IPv6AcceptRA = mkForce false;
|
2024-11-30 17:45:59 +00:00
|
|
|
routes = [
|
2023-12-20 01:30:27 +00:00
|
|
|
{
|
|
|
|
Destination = lib.my.c.colony.prefixes.all.v4;
|
|
|
|
Gateway = allAssignments.estuary.as211024.ipv4.address;
|
|
|
|
}
|
2024-11-26 00:04:43 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
Destination = lib.my.c.tailscale.prefix.v4;
|
|
|
|
Gateway = allAssignments.britway.as211024.ipv4.address;
|
|
|
|
}
|
|
|
|
{
|
|
|
|
Destination = lib.my.c.tailscale.prefix.v6;
|
|
|
|
Gateway = allAssignments.britway.as211024.ipv6.address;
|
|
|
|
}
|
2023-12-20 01:30:27 +00:00
|
|
|
];
|
2023-11-26 01:29:44 +00:00
|
|
|
}
|
|
|
|
];
|
2023-11-18 22:54:43 +00:00
|
|
|
}
|
|
|
|
|
2023-12-16 15:59:33 +00:00
|
|
|
(mkVLANConfig "hi")
|
|
|
|
(mkVLANConfig "lo")
|
|
|
|
(mkVLANConfig "untrusted")
|
2023-12-16 13:00:10 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
"60-lan-hi" = {
|
2024-11-30 17:45:59 +00:00
|
|
|
routes = [
|
2023-12-16 13:00:10 +00:00
|
|
|
{
|
|
|
|
Destination = elemAt routersPubV4 otherIndex;
|
|
|
|
Gateway = net.cidr.host (otherIndex + 1) prefixes.hi.v4;
|
|
|
|
}
|
|
|
|
];
|
|
|
|
};
|
|
|
|
}
|
2023-11-18 22:54:43 +00:00
|
|
|
];
|
|
|
|
};
|
|
|
|
|
|
|
|
my = {
|
|
|
|
secrets = {
|
|
|
|
files = {
|
2023-11-26 01:29:44 +00:00
|
|
|
"l2mesh/as211024.key" = {};
|
2023-11-18 22:54:43 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2023-11-26 01:29:44 +00:00
|
|
|
vpns = {
|
|
|
|
l2.pskFiles = {
|
|
|
|
as211024 = config.age.secrets."l2mesh/as211024.key".path;
|
|
|
|
};
|
|
|
|
};
|
2023-11-18 22:54:43 +00:00
|
|
|
firewall = {
|
2024-11-26 00:04:43 +00:00
|
|
|
trustedInterfaces = [ "lan-hi" "lan-lo" ];
|
2023-11-18 22:54:43 +00:00
|
|
|
udp.allowed = [ 5353 ];
|
|
|
|
tcp.allowed = [ 5353 ];
|
|
|
|
nat = {
|
|
|
|
enable = true;
|
|
|
|
externalInterface = "wan";
|
|
|
|
};
|
2023-12-20 20:41:19 +00:00
|
|
|
extraRules =
|
|
|
|
let
|
|
|
|
aa = allAssignments;
|
|
|
|
in
|
|
|
|
''
|
2023-11-18 22:54:43 +00:00
|
|
|
table inet filter {
|
|
|
|
chain input {
|
2023-12-23 12:33:10 +00:00
|
|
|
${lib.my.c.as211024.nftTrust}
|
2023-11-18 22:54:43 +00:00
|
|
|
iifname base meta l4proto { udp, tcp } th dport domain accept
|
2023-12-11 02:31:26 +00:00
|
|
|
iifname lan-core meta l4proto vrrp accept
|
2023-11-18 22:54:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
chain routing-tcp {
|
2023-12-20 20:41:19 +00:00
|
|
|
ip daddr {
|
|
|
|
${aa.castle.hi.ipv4.address},
|
|
|
|
${aa.cellar.hi.ipv4.address},
|
|
|
|
${aa.palace.hi.ipv4.address}
|
|
|
|
} tcp dport ssh accept
|
|
|
|
ip6 daddr {
|
|
|
|
${aa.castle.hi.ipv6.address},
|
|
|
|
${aa.cellar.hi.ipv6.address},
|
|
|
|
${aa.palace.hi.ipv6.address}
|
|
|
|
} tcp dport ssh accept
|
2023-11-18 22:54:43 +00:00
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
chain routing-udp {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
chain filter-routing {
|
|
|
|
tcp flags & (fin|syn|rst|ack) == syn ct state new jump routing-tcp
|
|
|
|
meta l4proto udp ct state new jump routing-udp
|
|
|
|
return
|
|
|
|
}
|
|
|
|
chain filter-untrusted {
|
|
|
|
ip daddr ${prefixes.modem.v4} reject
|
|
|
|
oifname wan accept
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-03-21 20:42:06 +00:00
|
|
|
chain forward-early {
|
|
|
|
type filter hook forward priority -1; policy accept;
|
|
|
|
|
|
|
|
# MSS clamping to workaround IPv6 PMTUD being broken...
|
|
|
|
tcp flags syn tcp option maxseg size set rt mtu counter
|
2024-06-05 20:21:48 +01:00
|
|
|
|
|
|
|
# More Disney+ discrimination...
|
|
|
|
# TODO: This prefix could change (random AWS block)
|
|
|
|
ip6 daddr 2600:9000:2245::/48 drop
|
2024-03-21 20:42:06 +00:00
|
|
|
}
|
2023-11-18 22:54:43 +00:00
|
|
|
chain forward {
|
2023-12-20 22:59:51 +00:00
|
|
|
${lib.my.c.as211024.nftTrust}
|
2023-11-19 22:05:24 +00:00
|
|
|
iifname lan-untrusted jump filter-untrusted
|
2023-12-20 22:59:51 +00:00
|
|
|
iifname { wan, as211024, lan-untrusted } oifname { lan-hi, lan-lo } jump filter-routing
|
|
|
|
oifname as211024 accept
|
2023-11-18 22:54:43 +00:00
|
|
|
}
|
|
|
|
chain output { }
|
|
|
|
}
|
|
|
|
table inet nat {
|
|
|
|
chain prerouting {
|
2023-12-03 22:58:28 +00:00
|
|
|
ip daddr ${elemAt routersPubV4 index} meta l4proto { udp, tcp } th dport domain redirect to :5353
|
|
|
|
ip6 daddr ${assignments.as211024.ipv6.address} meta l4proto { udp, tcp } th dport domain redirect to :5353
|
2023-11-18 22:54:43 +00:00
|
|
|
}
|
|
|
|
chain postrouting {
|
|
|
|
oifname wan masquerade
|
|
|
|
}
|
|
|
|
}
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|