diff --git a/nixos/lib/vargen/main.go b/nixos/lib/vargen/main.go index 8957b6e..8d35268 100644 --- a/nixos/lib/vargen/main.go +++ b/nixos/lib/vargen/main.go @@ -58,9 +58,9 @@ func main() { var ( // Trusted subnets which will have internal DNS and other services // deployed on them. - enp2s0 = newSubnet("enp2s0", 0, gua6, trusted) - lan0 = newSubnet("lan0", 10, gua6, trusted) - wg0 = newSubnet("wg0", 20, gua6, trusted) + mgmt0 = newSubnet("mgmt0", 0, gua6, trusted) + lan0 = newSubnet("lan0", 10, gua6, trusted) + wg0 = newSubnet("wg0", 20, gua6, trusted) // When multiple subnets are available, prefer the 10GbE subnet. tengb0 = func() subnet { @@ -78,14 +78,14 @@ func main() { server = newHost( "servnerr-3", - enp2s0, + mgmt0, netaddr.MustParseIP("192.168.1.6"), mac("1c:1b:0d:ea:83:0f"), ) desktop = newHost( "nerr-3", - enp2s0, + mgmt0, netaddr.MustParseIP("192.168.1.7"), mac("04:d9:f5:7e:1c:47"), ) @@ -129,25 +129,25 @@ func main() { Infra: []host{ newHost( "switch-livingroom01", - enp2s0, + mgmt0, netaddr.MustParseIP("192.168.1.2"), mac("f0:9f:c2:0b:28:ca"), ), newHost( "switch-office01", - enp2s0, + mgmt0, netaddr.MustParseIP("192.168.1.3"), mac("f0:9f:c2:ce:7e:e1"), ), newHost( "switch-office02", - enp2s0, + mgmt0, netaddr.MustParseIP("192.168.1.4"), mac("74:ac:b9:e2:4e:a5"), ), newHost( "ap-livingroom02", - enp2s0, + mgmt0, netaddr.MustParseIP("192.168.1.5"), mac("74:83:c2:7a:c6:15"), ), @@ -188,7 +188,7 @@ func main() { } // Attach interface definitions from subnet definitions. - out.addInterface("enp2s0", enp2s0) + out.addInterface("mgmt0", mgmt0) out.addInterface("lan0", lan0) out.addInterface("guest0", guest0) out.addInterface("iot0", iot0) @@ -201,7 +201,7 @@ func main() { // TODO: WANs are special cases and should probably live in their own // section with different rules. out.Interfaces["wan0"] = iface{ - Name: "enp1s0", + Name: "wan0", Preference: medium, IPv4: wan4, } diff --git a/nixos/lib/vars.json b/nixos/lib/vars.json index 4ceb41e..9efb379 100644 --- a/nixos/lib/vars.json +++ b/nixos/lib/vars.json @@ -149,17 +149,6 @@ ] }, "interfaces": { - "enp2s0": { - "name": "enp2s0", - "preference": "medium", - "internal_dns": true, - "ipv4": "192.168.1.1", - "ipv6": { - "gua": "2600:6c4a:787f:1900::1", - "ula": "fd9e:1a04:f01d::1", - "lla": "fe80::1" - } - }, "guest0": { "name": "guest0", "preference": "medium", @@ -204,8 +193,19 @@ "lla": "fe80::1" } }, + "mgmt0": { + "name": "mgmt0", + "preference": "medium", + "internal_dns": true, + "ipv4": "192.168.1.1", + "ipv6": { + "gua": "2600:6c4a:787f:1900::1", + "ula": "fd9e:1a04:f01d::1", + "lla": "fe80::1" + } + }, "wan0": { - "name": "enp1s0", + "name": "wan0", "preference": "medium", "internal_dns": false, "ipv4": "24.247.223.150", diff --git a/nixos/routnerr-2/configuration.nix b/nixos/routnerr-2/configuration.nix index b11a100..1b1a1bf 100644 --- a/nixos/routnerr-2/configuration.nix +++ b/nixos/routnerr-2/configuration.nix @@ -104,7 +104,7 @@ in { avahi = { enable = true; interfaces = with vars.interfaces; [ - "${enp2s0.name}" + "${mgmt0.name}" "${lan0.name}" "${iot0.name}" ]; diff --git a/nixos/routnerr-2/corerad.nix b/nixos/routnerr-2/corerad.nix index dcef806..3dbbf68 100644 --- a/nixos/routnerr-2/corerad.nix +++ b/nixos/routnerr-2/corerad.nix @@ -26,7 +26,7 @@ in { }) # Downstream advertising interfaces. - ++ lib.forEach [ enp2s0 lab0 lan0 guest0 iot0 ] (ifi: + ++ lib.forEach [ mgmt0 lab0 lan0 guest0 iot0 ] (ifi: { name = ifi.name; advertise = true; diff --git a/nixos/routnerr-2/dhcpd4.nix b/nixos/routnerr-2/dhcpd4.nix index d0f787f..5228225 100644 --- a/nixos/routnerr-2/dhcpd4.nix +++ b/nixos/routnerr-2/dhcpd4.nix @@ -2,7 +2,7 @@ let vars = import ./lib/vars.nix; - lans = with vars.interfaces; [ enp2s0 lan0 guest0 iot0 lab0 ]; + lans = with vars.interfaces; [ mgmt0 lan0 guest0 iot0 lab0 ]; in { services.dhcpd4 = { diff --git a/nixos/routnerr-2/networking.nix b/nixos/routnerr-2/networking.nix index ad1d9ed..5032e35 100644 --- a/nixos/routnerr-2/networking.nix +++ b/nixos/routnerr-2/networking.nix @@ -3,80 +3,21 @@ let vars = import ./lib/vars.nix; - # Produces the configuration for a LAN interface. - mkInterface = (ifi: { - ipv4.addresses = [{ - address = "${ifi.ipv4}"; - prefixLength = 24; - }]; - ipv6.addresses = [{ - address = "${ifi.ipv6.ula}"; - prefixLength = 64; - }]; - tempAddress = "disabled"; - }); - mkPeer = (peer: { publicKey = peer.public_key; allowedIPs = peer.allowed_ips; }); in { - # LAN interface. networking = { hostName = "routnerr-2"; + # TODO(mdlayher): systemd-resolved with fallback nameservers. nameservers = with vars.localhost; [ "${ipv4}" "${ipv6}" ]; - dhcpcd = { - enable = true; - # Do not remove interface configuration on shutdown. - persistent = true; - allowInterfaces = [ "${vars.interfaces.wan0.name}" ]; - extraConfig = with vars.interfaces; '' - noipv6rs - interface ${wan0.name} - ipv6rs - # DHCPv6-PD. - ia_na 0 - ia_pd 1/::/56 ${enp2s0.name}/0/64 ${lab0.name}/2/64 ${guest0.name}/9/64 ${lan0.name}/10/64 ${iot0.name}/66/64 - - # IPv4 DHCP ISP settings overrides. - static domain_name_servers=${vars.localhost.ipv4} - static domain_search= - static domain_name= - ''; - }; - - interfaces = with vars.interfaces; { - # WAN interface: allow dhcpcd and NM to coexist. - ${wan0.name}.useDHCP = true; - - # LAN interfaces. - ${enp2s0.name} = mkInterface enp2s0; - ${lan0.name} = mkInterface lan0; - ${lab0.name} = mkInterface lab0; - ${guest0.name} = mkInterface guest0; - ${iot0.name} = mkInterface iot0; - }; - - vlans = with vars.interfaces; { - ${lab0.name} = { - id = 2; - interface = "${enp2s0.name}"; - }; - ${guest0.name} = { - id = 9; - interface = "${enp2s0.name}"; - }; - ${lan0.name} = { - id = 10; - interface = "${enp2s0.name}"; - }; - ${iot0.name} = { - id = 66; - interface = "${enp2s0.name}"; - }; - }; + # Use systemd-networkd for configuration. Forcibly disable legacy DHCP + # client. + useNetworkd = true; + useDHCP = false; wireguard = with vars.wireguard; { enable = true; @@ -95,26 +36,145 @@ in { }; }; + # Use nftables instead. nat.enable = false; firewall.enable = false; + }; - # Use NM/MM only to manage the LTE modem. - networkmanager = { - enable = false; - dns = "none"; - unmanaged = [ "*,except:type:gsm" ]; + # TODO(mdlayher): enable after working out CoreDNS dependency. + services.resolved.enable = false; + + # Manage network configuration with networkd. + # + # TODO(mdlayher): template out again. + systemd.network = { + enable = true; + + # Wired WAN. + links."10-wan0" = { + matchConfig.MACAddress = "00:0d:b9:53:ea:cc"; + linkConfig.Name = "wan0"; + }; + networks."10-wan0" = { + matchConfig.Name = "wan0"; + networkConfig.DHCP = "yes"; + # Never accept ISP DNS or search domains. + dhcpV4Config = { + UseDNS = false; + UseDomains = false; + }; + dhcpV6Config = { + # Spectrum gives a /56. + PrefixDelegationHint = "::/56"; + + UseDNS = false; + # TODO(mdlayher): NixOS doesn't allow this? + # UseDomains = false; + }; + ipv6AcceptRAConfig = { + UseDNS = false; + UseDomains = false; + }; + }; + + # TODO(mdlayher): wireless WAN. + + # Physical management LAN. + links."11-mgmt0" = { + # Important: match on Ethernet device type because VLANs share this MAC. + matchConfig = { + Type = "ether"; + MACAddress = "00:0d:b9:53:ea:cd"; + }; + linkConfig.Name = "mgmt0"; + }; + networks."11-mgmt0" = { + matchConfig.Name = "mgmt0"; + address = [ "fd9e:1a04:f01d::1/64" "192.168.1.1/24" ]; + + # VLANs associated with this physical interface. + vlan = [ "lan0" "iot0" "guest0" "lab0" ]; + + networkConfig.DHCPv6PrefixDelegation = true; + dhcpV6PrefixDelegationConfig = { + Token = "::1"; + SubnetId = 0; + }; + }; + + # Home VLAN. + netdevs."12-lan0" = { + netdevConfig = { + Name = "lan0"; + Kind = "vlan"; + }; + vlanConfig.Id = 10; + }; + networks."12-lan0" = { + matchConfig.Name = "lan0"; + address = [ "fd9e:1a04:f01d:10::1/64" "192.168.10.1/24" ]; + networkConfig.DHCPv6PrefixDelegation = true; + dhcpV6PrefixDelegationConfig = { + Token = "::1"; + SubnetId = "a"; + }; + }; + + # IoT VLAN. + netdevs."13-iot0" = { + netdevConfig = { + Name = "iot0"; + Kind = "vlan"; + }; + vlanConfig.Id = 66; + }; + networks."13-iot0" = { + matchConfig.Name = "iot0"; + address = [ "fd9e:1a04:f01d:66::1/64" "192.168.66.1/24" ]; + networkConfig.DHCPv6PrefixDelegation = true; + dhcpV6PrefixDelegationConfig = { + Token = "::1"; + SubnetId = "42"; + }; + }; + + # Guest VLAN. + netdevs."14-guest0" = { + netdevConfig = { + Name = "guest0"; + Kind = "vlan"; + }; + vlanConfig.Id = 9; + }; + networks."14-guest0" = { + matchConfig.Name = "guest0"; + address = [ "fd9e:1a04:f01d:9::1/64" "192.168.9.1/24" ]; + networkConfig.DHCPv6PrefixDelegation = true; + dhcpV6PrefixDelegationConfig = { + Token = "::1"; + SubnetId = "9"; + }; + }; + + # Lab VLAN. + netdevs."15-lab0" = { + netdevConfig = { + Name = "lab0"; + Kind = "vlan"; + }; + vlanConfig.Id = 2; + }; + networks."15-lab0" = { + matchConfig.Name = "lab0"; + address = [ "fd9e:1a04:f01d:2::1/64" "192.168.2.1/24" ]; + networkConfig.DHCPv6PrefixDelegation = true; + dhcpV6PrefixDelegationConfig = { + Token = "::1"; + SubnetId = "2"; + }; }; }; - # Bring up MM and exporter with NM. - systemd.services.ModemManager = { - enable = false; - wantedBy = [ "NetworkManager.service" ]; - }; - - # Tailscale experiments to replace WireGuard full-tunnel VPN. - services.tailscale.enable = false; - # Enable WireGuard Prometheus exporter and set up peer key/name mappings. # TODO: nixify the configuration. services.wireguard_exporter = { diff --git a/nixos/routnerr-2/nftables.nix b/nixos/routnerr-2/nftables.nix index 90e719b..90793c5 100644 --- a/nixos/routnerr-2/nftables.nix +++ b/nixos/routnerr-2/nftables.nix @@ -31,8 +31,8 @@ let all_wans = with vars.interfaces; [ wan0 wwan0 ]; # LAN interfaces, segmented into trusted, limited, and untrusted groups. - metered_lans = with vars.interfaces; [ enp2s0 lan0 ]; - trusted_lans = with vars.interfaces; [ enp2s0 lan0 lab0 wg0 ]; + metered_lans = with vars.interfaces; [ mgmt0 lan0 ]; + trusted_lans = with vars.interfaces; [ mgmt0 lan0 lab0 wg0 ]; limited_lans = with vars.interfaces; [ guest0 ]; untrusted_lans = with vars.interfaces; [ iot0 ];