Jack O'Sullivan
0e115544e4
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 17m13s
358 lines
11 KiB
Nix
358 lines
11 KiB
Nix
index: { lib, ... }:
|
|
let
|
|
inherit (builtins) elemAt;
|
|
inherit (lib.my) net;
|
|
inherit (lib.my.c) pubDomain;
|
|
inherit (lib.my.c.home) domain vlans prefixes routers;
|
|
|
|
name = elemAt routers index;
|
|
in
|
|
{
|
|
nixos.systems."${name}" = {
|
|
assignments = {
|
|
modem = {
|
|
ipv4 = {
|
|
address = net.cidr.host (254 - index) prefixes.modem.v4;
|
|
gateway = null;
|
|
};
|
|
};
|
|
core = {
|
|
name = "${name}-core";
|
|
inherit domain;
|
|
ipv4 = {
|
|
address = net.cidr.host (index + 1) prefixes.core.v4;
|
|
gateway = null;
|
|
};
|
|
};
|
|
hi = {
|
|
inherit domain;
|
|
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;
|
|
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;
|
|
ipv4 = {
|
|
address = net.cidr.host (index + 1) prefixes.untrusted.v4;
|
|
mask = 24;
|
|
gateway = null;
|
|
};
|
|
ipv6.address = net.cidr.host (index + 1) prefixes.untrusted.v6;
|
|
};
|
|
};
|
|
|
|
configuration = { lib, pkgs, config, assignments, allAssignments, ... }:
|
|
let
|
|
inherit (lib) mkIf mkMerge mkForce;
|
|
inherit (lib.my) networkdAssignment;
|
|
|
|
# TODO: Move into nixpkgs
|
|
mstpd = pkgs.mstpd.overrideAttrs {
|
|
patches = [ ./mstpd.patch ];
|
|
};
|
|
in
|
|
{
|
|
imports = [ (import ./dns.nix index) ];
|
|
|
|
config = {
|
|
environment = {
|
|
systemPackages = [
|
|
pkgs.ethtool
|
|
mstpd
|
|
];
|
|
etc = {
|
|
"bridge-stp.conf".text = ''
|
|
MANAGE_MSTPD=n
|
|
MSTP_BRIDGES=lan
|
|
'';
|
|
};
|
|
};
|
|
|
|
services = {
|
|
resolved = {
|
|
llmnr = "false";
|
|
extraConfig = ''
|
|
MulticastDNS=false
|
|
'';
|
|
};
|
|
|
|
iperf3 = {
|
|
enable = true;
|
|
openFirewall = true;
|
|
};
|
|
|
|
networkd-dispatcher = {
|
|
enable = true;
|
|
rules = {
|
|
configure-mstpd = {
|
|
onState = [ "routable" ];
|
|
script = ''
|
|
#!${pkgs.runtimeShell}
|
|
if [ $IFACE = "lan" ]; then
|
|
${mstpd}/sbin/mstpctl setforcevers $IFACE rstp
|
|
fi
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
networking.domain = "h.${pubDomain}";
|
|
|
|
systemd = {
|
|
services = {
|
|
mstpd = {
|
|
description = "MSTP daemon";
|
|
before = [ "network-pre.target" ];
|
|
serviceConfig = {
|
|
Type = "forking";
|
|
ExecStart = "${mstpd}/sbin/bridge-stp restart";
|
|
ExecReload = "${mstpd}/sbin/bridge-stp restart_config";
|
|
PIDFile = "/run/mstpd.pid";
|
|
Restart = "always";
|
|
PrivateTmp = true;
|
|
ProtectHome = true;
|
|
};
|
|
wantedBy = [ "multi-user.target" ];
|
|
};
|
|
};
|
|
};
|
|
|
|
systemd.network = {
|
|
wait-online.enable = false;
|
|
config = {
|
|
networkConfig = {
|
|
ManageForeignRoutes = false;
|
|
};
|
|
};
|
|
|
|
netdevs =
|
|
let
|
|
mkVLAN = name: vid: {
|
|
"25-${name}" = {
|
|
netdevConfig = {
|
|
Name = name;
|
|
Kind = "vlan";
|
|
};
|
|
vlanConfig.Id = vid;
|
|
};
|
|
};
|
|
in
|
|
mkMerge [
|
|
{
|
|
"25-wan".netdevConfig = {
|
|
Name = "wan";
|
|
Kind = "bridge";
|
|
};
|
|
"25-lan" = {
|
|
netdevConfig = {
|
|
Name = "lan";
|
|
Kind = "bridge";
|
|
};
|
|
extraConfig = ''
|
|
[Bridge]
|
|
STP=true
|
|
'';
|
|
};
|
|
"30-lan-core".netdevConfig = {
|
|
Name = "lan-core";
|
|
Kind = "macvlan";
|
|
MTUBytes = "1500";
|
|
};
|
|
}
|
|
|
|
(mkVLAN "lan-hi" vlans.hi)
|
|
(mkVLAN "lan-lo" vlans.lo)
|
|
(mkVLAN "lan-untrusted" vlans.untrusted)
|
|
(mkVLAN "wan-tunnel" vlans.wan)
|
|
];
|
|
|
|
networks =
|
|
let
|
|
mkVLANConfig = name: mtu:
|
|
let
|
|
iface = "lan-${name}";
|
|
in
|
|
{
|
|
"60-${iface}" = mkMerge [
|
|
(networkdAssignment iface assignments."${name}")
|
|
{
|
|
linkConfig.MTUBytes = toString mtu;
|
|
domains = [ config.networking.domain ];
|
|
networkConfig = {
|
|
IPv6AcceptRA = mkForce false;
|
|
# IPv6SendRA = true;
|
|
};
|
|
ipv6SendRAConfig = {
|
|
DNS = [
|
|
(net.cidr.host 1 prefixes."${name}".v4)
|
|
(net.cidr.host 2 prefixes."${name}".v4)
|
|
(net.cidr.host 1 prefixes."${name}".v6)
|
|
(net.cidr.host 2 prefixes."${name}".v6)
|
|
];
|
|
Domains = [ config.networking.domain ];
|
|
};
|
|
ipv6Prefixes = [
|
|
{
|
|
ipv6PrefixConfig.Prefix = prefixes."${name}".v6;
|
|
}
|
|
];
|
|
}
|
|
];
|
|
};
|
|
in
|
|
mkMerge [
|
|
{
|
|
"50-wan-phy" = {
|
|
matchConfig.Name = "wan-phy";
|
|
networkConfig.Bridge = "wan";
|
|
};
|
|
"50-wan-tunnel" = {
|
|
matchConfig.Name = "wan-tunnel";
|
|
networkConfig.Bridge = "wan";
|
|
linkConfig.MTUBytes = "1500";
|
|
};
|
|
"50-wan" = mkMerge [
|
|
(networkdAssignment "wan" assignments.modem)
|
|
{
|
|
matchConfig.Name = "wan";
|
|
DHCP = "ipv4";
|
|
dns = [ "127.0.0.1" "::1" ];
|
|
dhcpV4Config.UseDNS = false;
|
|
routes = map (r: { routeConfig = r; }) [
|
|
# {
|
|
# Destination = prefixes.ctrs.v4;
|
|
# Gateway = allAssignments.shill.routing.ipv4.address;
|
|
# }
|
|
];
|
|
}
|
|
];
|
|
|
|
"50-lan-jim" = {
|
|
matchConfig.Name = "lan-jim";
|
|
networkConfig.Bridge = "lan";
|
|
};
|
|
"50-lan-dave" = {
|
|
matchConfig.Name = "lan-dave";
|
|
networkConfig.Bridge = "lan";
|
|
};
|
|
"55-lan" = {
|
|
matchConfig.Name = "lan";
|
|
vlan = [ "lan-hi" "lan-lo" "lan-untrusted" "wan-tunnel" ];
|
|
macvlan = [ "lan-core" ];
|
|
networkConfig = {
|
|
LinkLocalAddressing = "no";
|
|
IPv6AcceptRA = false;
|
|
LLDP = false;
|
|
EmitLLDP = false;
|
|
};
|
|
};
|
|
"60-lan-core" = mkMerge [
|
|
(networkdAssignment "lan-core" assignments.core)
|
|
{
|
|
matchConfig.Name = "lan-core";
|
|
networkConfig.IPv6AcceptRA = mkForce false;
|
|
}
|
|
];
|
|
}
|
|
|
|
(mkVLANConfig "hi" 9000)
|
|
(mkVLANConfig "lo" 1500)
|
|
(mkVLANConfig "untrusted" 1500)
|
|
];
|
|
};
|
|
|
|
my = {
|
|
secrets = {
|
|
files = {
|
|
# "estuary/kelder-wg.key" = {
|
|
# owner = "systemd-network";
|
|
# };
|
|
};
|
|
};
|
|
|
|
firewall = {
|
|
trustedInterfaces = [ "lan-hi" "lan-lo" ];
|
|
udp.allowed = [ 5353 ];
|
|
tcp.allowed = [ 5353 ];
|
|
nat = {
|
|
enable = true;
|
|
externalInterface = "wan";
|
|
# externalIP = assignments.internal.ipv4.address;
|
|
forwardPorts = [
|
|
# {
|
|
# port = "http";
|
|
# dst = allAssignments.middleman.internal.ipv4.address;
|
|
# }
|
|
];
|
|
};
|
|
extraRules =
|
|
let
|
|
aa = allAssignments;
|
|
matchInet = rule: sys: ''
|
|
ip daddr ${aa."${sys}".hi.ipv4.address} ${rule}
|
|
ip6 daddr ${aa."${sys}".hi.ipv6.address} ${rule}
|
|
'';
|
|
in
|
|
''
|
|
table inet filter {
|
|
chain input {
|
|
iifname base meta l4proto { udp, tcp } th dport domain accept
|
|
}
|
|
|
|
chain routing-tcp {
|
|
# Safe enough to allow all SSH
|
|
tcp dport ssh accept
|
|
|
|
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
|
|
}
|
|
|
|
chain forward {
|
|
iifname lan-untrusted jump filter-untrusted
|
|
iifname { wan, lan-untrusted } oifname { lan-hi, lan-lo } jump filter-routing
|
|
}
|
|
chain output { }
|
|
}
|
|
table inet nat {
|
|
chain prerouting {
|
|
${matchInet "meta l4proto { udp, tcp } th dport domain redirect to :5353" name}
|
|
}
|
|
chain postrouting {
|
|
oifname wan masquerade
|
|
}
|
|
}
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
}
|