diff --git a/flake.nix b/flake.nix index b3271c0..63701fb 100644 --- a/flake.nix +++ b/flake.nix @@ -116,11 +116,11 @@ nixos/boxes/colony nixos/boxes/tower nixos/boxes/castle + nixos/boxes/home/oxbow.nix nixos/boxes/kelder # Homes - # home-manager/configs/castle.nix - home-manager/configs/macsimum.nix + # home-manager/configs/macsimum.nix ]; nixfiles = evalModules { diff --git a/lib/constants.nix b/lib/constants.nix index ed8f4f2..faec06a 100644 --- a/lib/constants.nix +++ b/lib/constants.nix @@ -97,6 +97,54 @@ rec { interval = "04:45"; }; }; + home = rec { + domain = "h.${pubDomain}"; + vlans = { + hi = 100; + lo = 110; + untrusted = 120; + wan = 130; + }; + hiMTU = 9000; + prefixes = with lib.my.net.cidr; rec { + modem = { + v4 = "192.168.0.0/24"; + }; + all = { + v4 = "192.168.64.0/18"; + v6 = "2a0e:97c0:4d0::/60"; + }; + core = { + v4 = subnet 6 0 all.v4; + }; + hi = { + v4 = subnet 4 1 all.v4; + v6 = subnet 4 1 all.v6; + }; + lo = { + v4 = subnet 3 1 all.v4; + v6 = subnet 4 2 all.v6; + }; + untrusted = { + v4 = subnet 6 16 all.v4; + v6 = subnet 4 3 all.v6; + }; + }; + vips = with lib.my.net.cidr; { + hi = { + v4 = host (4*256-2) prefixes.hi.v4; + v6 = host 65535 prefixes.hi.v6; + }; + lo = { + v4 = host (8*256-2) prefixes.lo.v4; + v6 = host 65535 prefixes.lo.v6; + }; + untrusted = { + v4 = host 254 prefixes.untrusted.v4; + v6 = host 65535 prefixes.untrusted.v6; + }; + }; + }; kelder = { groups = { storage = 2000; diff --git a/nixos/boxes/home/oxbow.nix b/nixos/boxes/home/oxbow.nix new file mode 100644 index 0000000..54cf593 --- /dev/null +++ b/nixos/boxes/home/oxbow.nix @@ -0,0 +1,56 @@ +{ + imports = [ + (import ./routing-common { + index = 1; + name = "oxbow"; + }) + ]; + + config.nixos.systems.oxbow = { + system = "x86_64-linux"; + nixpkgs = "mine"; + home-manager = "mine"; + + configuration = { lib, pkgs, config, ... }: + let + inherit (lib); + in + { + config = { + boot = { + kernelParams = [ "intel_iommu=on" ]; + }; + + hardware = { + enableRedistributableFirmware = true; + cpu = { + intel.updateMicrocode = true; + }; + }; + + fileSystems = { + "/boot" = { + device = "/dev/disk/by-label/ESP"; + fsType = "vfat"; + }; + "/nix" = { + device = "/dev/disk/by-label/nix"; + fsType = "ext4"; + }; + "/persist" = { + device = "/dev/disk/by-label/persist"; + fsType = "ext4"; + neededForBoot = true; + }; + }; + + my = { + secrets = { + # key = "ssh-ed25519 "; + }; + server.enable = true; + }; + }; + }; + }; +} diff --git a/nixos/boxes/home/routing-common/default.nix b/nixos/boxes/home/routing-common/default.nix new file mode 100644 index 0000000..6785f99 --- /dev/null +++ b/nixos/boxes/home/routing-common/default.nix @@ -0,0 +1,286 @@ +{ index, name }: { lib, ... }: +let + inherit (lib.my) net; + inherit (lib.my.c.home) domain vlans prefixes; +in +{ + nixos.systems."${name}" = { + assignments = { + modem = { + ipv4.address = net.cidr.host (254 - index) prefixes.modem.v4; + }; + core = { + name = "${name}-core"; + inherit domain; + ipv4 = { + address = net.cidr.host (index + 1) prefixes.core.v4; + mask = 24; + }; + }; + 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; + in + { + config = { + environment = { + systemPackages = with pkgs; [ + ethtool + ]; + }; + + services = { + resolved = { + llmnr = "false"; + extraConfig = '' + MulticastDNS=false + ''; + }; + + iperf3 = { + enable = true; + openFirewall = true; + }; + }; + + 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"; + }; + } + + (mkVLAN "hi" vlans.hi) + (mkVLAN "lo" vlans.lo) + (mkVLAN "untrusted" vlans.untrusted) + (mkVLAN "wan-tunnel" vlans.wan) + ]; + + links = { + "10-lan-jim" = { + matchConfig = { + # Matching against MAC address seems to break VLAN interfaces + # (since they share the same MAC address) + Driver = "igb"; + Path = "pci-0000:01:00.0"; + }; + linkConfig = { + Name = "lan-jim"; + RxBufferSize = 4096; + TxBufferSize = 4096; + MTUBytes = toString lib.my.c.home.hiMTU; + }; + }; + }; + + networks = + let + mkVLANConfig = name: { + "60-${name}" = mkMerge [ + (networkdAssignment name assignments.hi) + { + dns = [ "127.0.0.1" "::1" ]; + 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"; + }; + "50-wan" = mkMerge [ + (networkdAssignment "wan" assignments.modem) + { + matchConfig.Name = "wan"; + DHCP = "ipv4"; + 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 = [ "hi" "lo" "untrusted" ]; + }; + } + + (mkVLANConfig "hi") + (mkVLANConfig "lo") + (mkVLANConfig "untrusted") + ]; + }; + + my = { + secrets = { + files = { + # "estuary/kelder-wg.key" = { + # owner = "systemd-network"; + # }; + }; + }; + + firewall = { + trustedInterfaces = [ "hi" "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 untrusted jump filter-untrusted + iifname { wan, untrusted } oifname { hi, 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 + } + } + ''; + }; + }; + }; + }; + }; +}