diff options
Diffstat (limited to 'config')
| -rw-r--r-- | config/default.nix | 4 | ||||
| -rw-r--r-- | config/networking/bridges.nix | 47 | ||||
| -rw-r--r-- | config/networking/default.nix | 202 | ||||
| -rw-r--r-- | config/networking/services/ap.nix | 277 | ||||
| -rw-r--r-- | config/networking/services/dhcp.nix | 36 | ||||
| -rw-r--r-- | config/networking/services/dns.nix | 35 | ||||
| -rw-r--r-- | config/networking/services/firewall/default.nix | 80 | ||||
| -rw-r--r-- | config/networking/services/firewall/ruleset.nix | 68 | ||||
| -rw-r--r-- | config/networking/services/ifplugd.nix | 12 | ||||
| -rw-r--r-- | config/networking/services/igmpproxy.nix | 31 |
10 files changed, 387 insertions, 405 deletions
diff --git a/config/default.nix b/config/default.nix index 976c008..81e202a 100644 --- a/config/default.nix +++ b/config/default.nix @@ -9,6 +9,10 @@ ./users.nix ]; + # needed so that the server doesn't rebuild big packages + # originally enabled in modulesPath + profiles/minimal.nix + environment.noXlibs = false; + # This value determines the NixOS release from which the default # settings for stateful data, like file locations and database versions # on your system were taken. It‘s perfectly fine and recommended to leave diff --git a/config/networking/bridges.nix b/config/networking/bridges.nix index e423e03..eecd34e 100644 --- a/config/networking/bridges.nix +++ b/config/networking/bridges.nix @@ -4,29 +4,30 @@ pkgs, ... }: let - nets = config.personal.networking.networks; + bridges = config.personal.networking.interfaces.bridges; in { - config = lib.mkMerge ([ - { - systemd.services.hostapd.postStart = lib.mkForce (lib.mkBefore '' - sleep 3 - ''); - } - ] - ++ (builtins.map (network: let - bridge = network.interface; - device = network.device; - in { - networking.bridges."${bridge}".interfaces = []; + config = { + networking.bridges = lib.mapAttrs (_: _: {interfaces = [];}) bridges; + systemd.services = lib.mkMerge ([ + { + hostapd.postStart = lib.mkBefore '' + sleep 10 + ''; + } + ] + ++ (lib.mapAttrsToList (bridge: {interfaces, ...}: { + "${bridge}-netdev".script = '' + echo Setting forward delay to 0 for ${bridge}... + ip link set ${bridge} type bridge forward_delay 0 + ''; - systemd.services."${bridge}-netdev".script = '' - echo Setting forward delay to 0 for ${bridge}... - ip link set ${bridge} type bridge forward_delay 0 - ''; - - systemd.services.hostapd.postStart = lib.mkForce '' - echo Setting ${device} to hairpin mode... - ${pkgs.iproute2}/bin/bridge link set dev ${device} hairpin on - ''; - }) [nets.wan nets.iot])); + hostapd.postStart = + lib.concatMapStringsSep "\n" (interface: '' + echo Setting ${interface} to hairpin mode... + ${pkgs.iproute2}/bin/bridge link set dev ${interface} hairpin on + '') + interfaces; + }) + bridges)); + }; } diff --git a/config/networking/default.nix b/config/networking/default.nix index 81efaf2..d1546d2 100644 --- a/config/networking/default.nix +++ b/config/networking/default.nix @@ -1,57 +1,16 @@ -# https://skogsbrus.xyz/blog/2022/06/12/router/ -# https://blog.fraggod.net/2017/04/27/wifi-hostapd-configuration-for-80211ac-networks.html { config, lib, ... }: let - cfg = config.personal.networking; + ifaces = config.personal.networking.interfaces; in { imports = [./bridges.nix ./services]; options.personal.networking = { - networks = lib.mkOption { - type = with lib.types; - attrsOf (submodule { - options = { - device = lib.mkOption { - type = with lib.types; nullOr str; - default = null; - description = "Name of the network device."; - example = "wlp1s0"; - }; - interface = lib.mkOption { - type = lib.types.str; - description = "Name of the network interface."; - example = "enp4s0"; - }; - subnet = lib.mkOption { - type = lib.types.str; - description = "IPv4 subnet of the network."; - example = "192.168.1"; - }; - machines = lib.mkOption { - type = with lib.types; - attrsOf (submodule { - options = { - ip = lib.mkOption { - type = lib.types.str; - description = "IP address of this machine."; - example = "192.168.1.1"; - }; - mac = lib.mkOption { - type = with lib.types; nullOr str; - description = "MAC address of this machine."; - default = null; - example = "01:23:45:67:89:ab"; - }; - }; - }); - description = "Some machines connected to this network."; - }; - }; - }); - description = "Networks this device belongs to."; + interfaces = lib.mkOption { + type = with lib.types; attrsOf anything; + description = "Available interfaces."; }; }; @@ -59,82 +18,137 @@ in { personal.networking = { enable = true; ssh.enable = true; - networks = { - lan = let - device = "enp4s0"; - in { - inherit device; - interface = device; - subnet = "192.168.1"; - machines = { - livebox = {ip = "192.168.1.1";}; - self = {ip = "192.168.1.2";}; + interfaces = let + devices = { + enp2s0.machines.self.mac = "00:0d:b9:5f:58:f0"; + enp3s0 = { + subnet = { + prefix = "192.168.4"; + prefixLength = 24; + }; + machines = { + self = { + mac = "00:0d:b9:5f:58:f1"; + ip = "192.168.4.1"; + }; + steam-deck = { + mac = "10:82:86:22:90:17"; + ip = "192.168.4.10"; + }; + }; + }; + enp4s0 = { + subnet = { + prefix = "192.168.1"; + prefixLength = 24; + }; + machines = { + self = { + mac = "00:0d:b9:5f:58:f2"; + ip = "192.168.1.2"; + }; + livebox.ip = "192.168.1.1"; + }; + }; + wlp1s0 = { + bridges = ["wan"]; + machines.self.mac = "04:f0:21:b6:11:fc"; + }; + wlp5s0 = { + bridges = ["wan"]; + machines.self.mac = "04:f0:21:b2:61:09"; }; }; - wan = { - device = "wlp1s0"; - interface = "wan"; - subnet = "192.168.2"; - machines = {self.ip = "192.168.2.1";}; + wlan = { + wlp1s0-iot = { + device = "wlp1s0"; + machines.self.mac = "02:f0:21:b6:11:fc"; + bridges = ["iot"]; + }; + wlp5s0-iot = { + device = "wlp5s0"; + machines.self.mac = "02:f0:21:b2:61:09"; + bridges = ["iot"]; + }; + wlp5s0-guest = { + device = "wlp5s0"; + machines.self.mac = "06:f0:21:b2:61:09"; + bridges = ["guest"]; + }; }; - iot = { - device = "wlp5s0"; - interface = "iot"; - subnet = "192.168.3"; - machines = { - self.ip = "192.168.3.1"; - sonos-move = { - ip = "192.168.3.10"; - mac = "54:2a:1b:73:7a:1e"; + bridges = { + wan = { + interfaces = ["wlp1s0" "wlp5s0"]; + subnet = { + prefix = "192.168.2"; + prefixLength = 24; }; - sonos-play1 = { - ip = "192.168.3.11"; - mac = "5c:aa:fd:44:b2:6a"; + machines.self.ip = "192.168.2.1"; + }; + iot = { + interfaces = ["wlp1s0-iot" "wlp5s0-iot"]; + subnet = { + prefix = "192.168.3"; + prefixLength = 24; + }; + machines = { + self.ip = "192.168.3.1"; + sonos-move = { + ip = "192.168.3.10"; + mac = "54:2a:1b:73:7a:1e"; + }; + sonos-play1 = { + ip = "192.168.3.11"; + mac = "5c:aa:fd:44:b2:6a"; + }; }; }; - }; - eth0 = { - device = "enp3s0"; - interface = "enp3s0"; - subnet = "192.168.4"; - machines = { - self.ip = "192.168.4.1"; - steam-deck = { - ip = "192.168.4.10"; - mac = "10:82:86:22:90:17"; + guest = { + interfaces = ["wlp5s0-guest"]; + subnet = { + prefix = "192.168.5"; + prefixLength = 24; }; + machines.self.ip = "192.168.5.1"; }; }; + in { + inherit devices wlan bridges; + all = devices // wlan // bridges; }; }; networking = { hostName = "kerberos"; domain = "local"; - nameservers = [cfg.networks.lan.machines.livebox.ip]; - defaultGateway = with cfg.networks.lan; { + nameservers = [ + # quad9 + "9.9.9.9" + "149.112.112.112" + # isp + config.networking.defaultGateway.address + ]; + defaultGateway = let + interface = "enp4s0"; + in { inherit interface; - address = machines.livebox.ip; + address = ifaces.all."${interface}".machines.livebox.ip; }; useDHCP = false; dhcpcd.enable = false; + interfaces = - lib.concatMapAttrs (_: { - interface, - machines, - ... - }: { + lib.concatMapAttrs (interface: attrs: { "${interface}" = { - useDHCP = false; - ipv4.addresses = lib.optional (machines ? self) { - address = machines.self.ip; + ipv4.addresses = lib.optional (attrs ? machines.self.ip) { + address = attrs.machines.self.ip; prefixLength = 24; }; }; }) - cfg.networks; + ifaces.all; }; }; } diff --git a/config/networking/services/ap.nix b/config/networking/services/ap.nix index 33bae8c..2248f5d 100644 --- a/config/networking/services/ap.nix +++ b/config/networking/services/ap.nix @@ -1,187 +1,128 @@ { config, lib, - utils, - pkgs, - secrets, ... }: let - nets = config.personal.networking.networks; - makeHostapdConf = { - name, - device, - interface, - driver ? "nl80211", - ssid, - hwMode ? "g", - channel ? 0, - countryCode ? "FR", - passphrase ? secrets.wifi."${name}".passphrase, - logLevel ? 2, - extraConfig ? "", - }: - builtins.toFile "hostapd.${name}.conf" ('' - interface=${device} - driver=${driver} + ifaces = config.personal.networking.interfaces.all; + netdevServices = builtins.map (bridge: "${bridge}-netdev.service") ["wan" "iot" "guest"]; - # IEEE 802.11 - ssid=${ssid} - hw_mode=${hwMode} - channel=${toString channel} - max_num_sta=128 - auth_algs=1 - disassoc_low_ack=1 - - # DFS - ieee80211h=1 - ieee80211d=1 - country_code=${countryCode} + # common config + countryCode = "FR"; + driver = "nl80211"; + settings.max_num_sta = 128; + perBridgeCfg = radio: bridge: let + ssids = { + wan = "Quentintranet"; + iot = "Quentinternet of Things"; + guest = "Quentinvités"; + }; + iface = radio + lib.optionalString (bridge != "wan") "-${bridge}"; + in { + "${iface}" = { + ssid = ssids."${bridge}" + lib.optionalString (radio == "wlp5s0" && bridge != "guest") " (n)"; + bssid = ifaces."${iface}".machines.self.mac; - # disable low-level bridging of frames - ap_isolate=1 - bridge=${interface} + authentication.mode = "wpa3-sae"; + authentication.saePasswordsFile = "/etc/hostapd/${bridge}.sae"; - # WPA/IEEE 802.11i - wpa=2 - wpa_key_mgmt=WPA-PSK - wpa_passphrase=${passphrase} - wpa_pairwise=CCMP + logLevel = 2; # informational messages - # hostapd event logger configuration - logger_syslog=-1 - logger_syslog_level=${toString logLevel} - logger_stdout=-1 - logger_stdout_level=${toString logLevel} + apIsolate = true; + settings = { + inherit bridge; + disassoc_low_ack = 1; # WMM - wmm_enabled=1 - uapsd_advertisement_enabled=1 - wmm_ac_bk_cwmin=4 - wmm_ac_bk_cwmax=10 - wmm_ac_bk_aifs=7 - wmm_ac_bk_txop_limit=0 - wmm_ac_bk_acm=0 - wmm_ac_be_aifs=3 - wmm_ac_be_cwmin=4 - wmm_ac_be_cwmax=10 - wmm_ac_be_txop_limit=0 - wmm_ac_be_acm=0 - wmm_ac_vi_aifs=2 - wmm_ac_vi_cwmin=3 - wmm_ac_vi_cwmax=4 - wmm_ac_vi_txop_limit=94 - wmm_ac_vi_acm=0 - wmm_ac_vo_aifs=2 - wmm_ac_vo_cwmin=2 - wmm_ac_vo_cwmax=3 - wmm_ac_vo_txop_limit=47 - wmm_ac_vo_acm=0 - - # TX queue parameters - tx_queue_data3_aifs=7 - tx_queue_data3_cwmin=15 - tx_queue_data3_cwmax=1023 - tx_queue_data3_burst=0 - tx_queue_data2_aifs=3 - tx_queue_data2_cwmin=15 - tx_queue_data2_cwmax=63 - tx_queue_data2_burst=0 - tx_queue_data1_aifs=1 - tx_queue_data1_cwmin=7 - tx_queue_data1_cwmax=15 - tx_queue_data1_burst=3.0 - tx_queue_data0_aifs=1 - tx_queue_data0_cwmin=3 - tx_queue_data0_cwmax=7 - tx_queue_data0_burst=1.5 - '' - + extraConfig); - hostapdIotConf = makeHostapdConf { - name = "iot"; - inherit (nets.iot) device interface; - ssid = "Quentinternet of Things"; - hwMode = "g"; - channel = 0; - extraConfig = '' - # IEEE 802.11n - ieee80211n=1 - require_ht=0 # sonos play:1 doesn't support ht - ht_capab=[HT40+][SHORT-GI-40][TX-STBC][RX-STBC1][DSSS_CCK-40] - ''; - }; - hostapdWanConf = makeHostapdConf { - name = "wan"; - inherit (nets.wan) device interface; - ssid = "Quentintranet"; - hwMode = "a"; - channel = 36; - extraConfig = '' - # IEEE 802.11n - ieee80211n=1 - require_ht=1 - ht_capab=[HT40+][LDPC][SHORT-GI-20][SHORT-GI-40][TX-STBC][RX-STBC1][DSSS_CCK-40] - - # IEEE 802.11ac - require_vht=1 - ieee80211ac=1 - vht_oper_chwidth=1 - vht_oper_centr_freq_seg0_idx=42 - vht_capab=[MAX-MPDU-11454][RXLDPC][SHORT-GI-80][TX-STBC-2BY1][RX-STBC-1][MAX-A-MPDU-LEN-EXP7][RX-ANTENNA-PATTERN][TX-ANTENNA-PATTERN] - ''; + wmm_enabled = 1; + uapsd_advertisement_enabled = 1; + wmm_ac_bk_cwmin = 4; + wmm_ac_bk_cwmax = 10; + wmm_ac_bk_aifs = 7; + wmm_ac_bk_txop_limit = 0; + wmm_ac_bk_acm = 0; + wmm_ac_be_aifs = 3; + wmm_ac_be_cwmin = 4; + wmm_ac_be_cwmax = 10; + wmm_ac_be_txop_limit = 0; + wmm_ac_be_acm = 0; + wmm_ac_vi_aifs = 2; + wmm_ac_vi_cwmin = 3; + wmm_ac_vi_cwmax = 4; + wmm_ac_vi_txop_limit = 94; + wmm_ac_vi_acm = 0; + wmm_ac_vo_aifs = 2; + wmm_ac_vo_cwmin = 2; + wmm_ac_vo_cwmax = 3; + wmm_ac_vo_txop_limit = 47; + wmm_ac_vo_acm = 0; + # TX queue + tx_queue_data3_aifs = 7; + tx_queue_data3_cwmin = 15; + tx_queue_data3_cwmax = 1023; + tx_queue_data3_burst = 0; + tx_queue_data2_aifs = 3; + tx_queue_data2_cwmin = 15; + tx_queue_data2_cwmax = 63; + tx_queue_data2_burst = 0; + tx_queue_data1_aifs = 1; + tx_queue_data1_cwmin = 7; + tx_queue_data1_cwmax = 15; + tx_queue_data1_burst = "3.0"; + tx_queue_data0_aifs = 1; + tx_queue_data0_cwmin = 3; + tx_queue_data0_cwmax = 7; + tx_queue_data0_burst = "1.5"; + }; + }; }; in { - systemd.services.hostapd = let - subnets = with nets; [wan iot]; - netDevices = - builtins.map (subnet: "sys-subsystem-net-devices-${ - utils.escapeSystemdPath subnet.device - }.device") - subnets; - netdevServices = - builtins.map (subnet: "${subnet.interface}-netdev.service") subnets; - dependencies = lib.mkForce (netDevices ++ netdevServices); - in - lib.mkForce { - # from https://github.com/NixOS/nixpkgs/blob/23.05/nixos/modules/services/networking/hostapd.nix - # with hardening from https://github.com/NixOS/nixpkgs/blob/23.11/nixos/modules/services/networking/hostapd.nix - description = "IEEE 802.11 Host Access-Point Daemon"; + systemd.services.hostapd = { + after = netdevServices; + bindsTo = netdevServices; + }; - path = [pkgs.hostapd]; - after = dependencies; - bindsTo = dependencies; - wantedBy = ["multi-user.target"]; + services.hostapd = { + enable = true; + radios = { + wlp1s0 = { + inherit countryCode driver; + band = "5g"; + channel = 36; + wifi4 = { + enable = true; + require = true; + capabilities = ["HT40+" "LDPC" "SHORT-GI-20" "SHORT-GI-40" "TX-STBC" "RX-STBC1" "DSSS_CCK-40"]; + }; + wifi5 = { + enable = true; + require = false; + operatingChannelWidth = "80"; + capabilities = ["MAX-MPDU-11454" "RXLDPC" "SHORT-GI-80" "TX-STBC-2BY1" "RX-STBC-1" "MAX-A-MPDU-LEN-EXP7" "RX-ANTENNA-PATTERN" "TX-ANTENNA-PATTERN"]; + }; + settings = settings // {vht_oper_centr_freq_seg0_idx = 42;}; - serviceConfig = { - ExecStart = "${pkgs.hostapd}/bin/hostapd ${hostapdIotConf} ${hostapdWanConf}"; - Restart = "always"; - ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; - RuntimeDirectory = "hostapd"; + networks = let + perBridgeAC = perBridgeCfg "wlp1s0"; + in + (perBridgeAC "wan") // (perBridgeAC "iot"); + }; + wlp5s0 = { + inherit countryCode driver settings; + band = "2g"; + channel = 0; + wifi4 = { + enable = true; + require = false; + capabilities = ["HT40+" "SHORT-GI-40" "TX-SBTC" "RX-SBTC1" "DSSS_CCK-40"]; + }; - # Hardening - LockPersonality = true; - MemoryDenyWriteExecute = true; - DevicePolicy = "closed"; - DeviceAllow = "/dev/rfkill rw"; - NoNewPrivileges = true; - PrivateUsers = false; # hostapd requires true root access. - PrivateTmp = true; - ProtectClock = true; - ProtectControlGroups = true; - ProtectHome = true; - ProtectHostname = true; - ProtectKernelLogs = true; - ProtectKernelModules = true; - ProtectKernelTunables = true; - ProtectProc = "invisible"; - ProcSubset = "pid"; - ProtectSystem = "strict"; - RestrictAddressFamilies = ["AF_INET" "AF_INET6" "AF_NETLINK" "AF_UNIX" "AF_PACKET"]; - RestrictNamespaces = true; - RestrictRealtime = true; - RestrictSUIDSGID = true; - SystemCallArchitectures = "native"; - SystemCallFilter = ["@system-service" "~@privileged" "@chown"]; - UMask = "0077"; + networks = let + perBridgeN = perBridgeCfg "wlp5s0"; + in + (perBridgeN "wan") + // (perBridgeN "iot") + // (perBridgeN "guest"); }; }; + }; } diff --git a/config/networking/services/dhcp.nix b/config/networking/services/dhcp.nix index e43d513..e513423 100644 --- a/config/networking/services/dhcp.nix +++ b/config/networking/services/dhcp.nix @@ -3,18 +3,18 @@ lib, ... }: let - nets = config.personal.networking.networks; + ifaces = config.personal.networking.interfaces; netdevServices = - builtins.map (subnet: "${subnet.interface}-netdev.service") - (with nets; [wan iot]); + builtins.map (iface: "${iface}-netdev.service") + ["wan" "iot" "guest"]; # not enp3s0 because it may come down for good reasons in { services.kea.dhcp4 = { enable = true; settings = let - subnets = with nets; [wan iot eth0]; + subnets = with ifaces; lib.filterAttrs (_: builtins.hasAttr "subnet") ifaces.all; in { interfaces-config = { - interfaces = builtins.map (network: network.interface) subnets; + interfaces = builtins.attrNames subnets; service-sockets-max-retries = 20; service-sockets-retry-wait-time = 5000; }; @@ -28,7 +28,7 @@ in { option-data = [ { name = "domain-name-servers"; - data = "${nets.lan.subnet}.1, 9.9.9.9"; + data = lib.concatStringsSep ", " config.networking.nameservers; } { name = "subnet-mask"; @@ -36,31 +36,33 @@ in { } ]; subnet4 = - builtins.map (network: { - subnet = "${network.subnet}.0/24"; + lib.mapAttrsToList (interface: { + subnet, + machines, + ... + }: { + subnet = "${subnet.prefix}.0/${builtins.toString subnet.prefixLength}"; option-data = [ { name = "broadcast-address"; - data = "${network.subnet}.255"; + data = "${subnet.prefix}.255"; } { name = "routers"; - data = network.machines.self.ip; + data = machines.self.ip; } ]; - inherit (network) interface; - pools = [{pool = "${network.subnet}.10 - ${network.subnet}.99";}]; - reservations = let - machines = builtins.attrValues (lib.filterAttrs (name: {mac, ...}: name != "self" && mac != null) network.machines); - in - builtins.map ({ + inherit interface; + pools = [{pool = "${subnet.prefix}.10 - ${subnet.prefix}.99";}]; + reservations = + lib.mapAttrsToList (_: { ip, mac, }: { hw-address = mac; ip-address = ip; }) - machines; + (lib.filterAttrs (name: addresses: name != "self" && addresses ? mac && addresses ? ip) machines); }) subnets; }; diff --git a/config/networking/services/dns.nix b/config/networking/services/dns.nix index 9e70958..5b4d99b 100644 --- a/config/networking/services/dns.nix +++ b/config/networking/services/dns.nix @@ -1,27 +1,28 @@ -{ config, ... }: - -let nets = config.personal.networking.networks; +{config, ...}: let + subnets = builtins.catAttrs "subnet" (builtins.attrValues config.personal.networking.interfaces.all); in { services.unbound = { enable = true; settings = { server = { module-config = ''"respip validator iterator"''; - interface = [ - "127.0.0.1" - "${nets.wan.subnet}.1" - "${nets.iot.subnet}.1" - "${nets.eth0.subnet}.1" - ]; - access-control = [ - "0.0.0.0/0 refuse" - "127.0.0.0/8 allow" - "${nets.wan.subnet}.0/24 allow" - "${nets.iot.subnet}.0/24 allow" - "${nets.eth0.subnet}.0/24 allow" - ]; + interface = + [ + "127.0.0.1" + ] + ++ builtins.map ({prefix, ...}: "${prefix}.1") subnets; + access-control = + [ + "0.0.0.0/0 refuse" + "127.0.0.0/8 allow" + ] + ++ builtins.map ({ + prefix, + prefixLength, + }: "${prefix}.0/${builtins.toString prefixLength} allow") + subnets; }; - rpz = { name = "rpz.oisd.nl"; }; + rpz.name = "rpz.oisd.nl"; }; }; } diff --git a/config/networking/services/firewall/default.nix b/config/networking/services/firewall/default.nix index d7a541f..1054a39 100644 --- a/config/networking/services/firewall/default.nix +++ b/config/networking/services/firewall/default.nix @@ -1,51 +1,65 @@ -{ config, lib, ... }: - -let +{ + config, + lib, + ... +}: let # { any } -> (string -> any -> string) -> string mapAttrsStrings = attrs: f: lib.concatStrings (lib.mapAttrsToList f attrs); bracket = title: content: '' ${title} { - '' + content + '' + '' + + content + + '' } ''; in { - boot.kernel.sysctl = { "net.ipv4.conf.all.forwarding" = true; }; + boot.kernel.sysctl = {"net.ipv4.conf.all.forwarding" = true;}; networking = { nftables = { enable = true; checkRuleset = false; - ruleset = mapAttrsStrings (import ./ruleset.nix { - inherit lib; - nets = config.personal.networking.networks; - }) (family: tables: - mapAttrsStrings tables (tableName: - { flowtables, chains, ... }: - bracket "table ${family} ${tableName}" ( - mapAttrsStrings flowtables - (flowtableName: flowtable: - bracket "flowtable ${flowtableName}" (with flowtable; - '' - hook ${hook} priority ${priority}; devices = { ${ - lib.concatStringsSep ", " devices - } }; - '' + lib.optionalString offload '' - flags offload; - '' - ) - ) - + mapAttrsStrings chains (chainName: chain: - bracket "chain ${chainName}" ( - lib.optionalString (chain ? base) (with chain.base; '' - type ${type} hook ${hook} priority ${priority}; policy ${policy}; - '') - + chain.rules + ruleset = + mapAttrsStrings (import ./ruleset.nix { + inherit lib; + inherit (config.personal.networking) interfaces; + }) ( + family: tables: + mapAttrsStrings tables ( + tableName: { + flowtables, + chains, + ... + }: + bracket "table ${family} ${tableName}" ( + mapAttrsStrings flowtables + ( + flowtableName: flowtable: + bracket "flowtable ${flowtableName}" ( + with flowtable; + '' + hook ${hook} priority ${priority}; devices = { ${ + lib.concatStringsSep ", " devices + } }; + '' + + lib.optionalString offload '' + flags offload; + '' + ) ) + + mapAttrsStrings chains ( + chainName: chain: + bracket "chain ${chainName}" ( + lib.optionalString (chain ? base) (with chain.base; '' + type ${type} hook ${hook} priority ${priority}; policy ${policy}; + '') + + chain.rules + ) + ) + ) ) - ) - ) - ); + ); }; firewall.enable = lib.mkForce false; }; diff --git a/config/networking/services/firewall/ruleset.nix b/config/networking/services/firewall/ruleset.nix index 055bc3c..e3427e4 100644 --- a/config/networking/services/firewall/ruleset.nix +++ b/config/networking/services/firewall/ruleset.nix @@ -1,7 +1,11 @@ -{ - lib, - nets, -}: let +{interfaces, ...}: let + machines = { + inherit + (interfaces.all.iot.machines) + sonos-play1 + sonos-move + ; + }; makeTable = args: { chains = {}; @@ -81,12 +85,14 @@ ''; player-controller = '' ip protocol udp \ - ip saddr { ${nets.iot.machines.sonos-move.ip} \ - , ${nets.iot.machines.sonos-play1.ip} } \ + ip saddr { ${machines.sonos-move.ip} \ + , ${machines.sonos-play1.ip} } \ udp sport >30000 \ udp dport >30000 \ accept comment "sonos: app control: player to controller" ip protocol tcp \ + ip saddr { ${machines.sonos-move.ip} \ + , ${machines.sonos-play1.ip} } \ tcp dport { 3400, 3401, 3500 } \ accept comment "sonos: app control: player to controller" ''; @@ -107,28 +113,30 @@ in { filter = makeTable { flowtables = { default = makeFlowtable { - devices = lib.mapAttrsToList (_: {device, ...}: device) nets; + devices = builtins.attrNames interfaces.devices; }; }; chains = { wan_in.rules = with rulesCommon; dns + dhcp + ssh + ssdp; iot_in.rules = with rulesCommon; dns + dhcp + igmp; - eth0_in.rules = with rulesCommon; dns + dhcp; + guest_in.rules = with rulesCommon; dns + dhcp; + enp3s0_in.rules = with rulesCommon; dns + dhcp; input = makeBaseChain "filter" "input" { rules = with rulesCommon; conntrack + ping + '' - meta iifname vmap { lo : accept \ - , ${nets.wan.interface} : goto wan_in \ - , ${nets.iot.interface} : goto iot_in \ - , ${nets.eth0.interface} : goto eth0_in } + meta iifname vmap { lo : accept \ + , wan : goto wan_in \ + , iot : goto iot_in \ + , guest : goto guest_in \ + , enp3s0 : goto enp3s0_in } ''; }; iot_wan.rules = rulesCommon.sonos.player-controller; wan_iot.rules = with rulesCommon; sonos.controller-player + ssdp; - wan_eth0.rules = rulesCommon.kdeconnect; - eth0_wan.rules = rulesCommon.kdeconnect; + wan_enp3s0.rules = rulesCommon.kdeconnect; + enp3s0_wan.rules = rulesCommon.kdeconnect; forward = makeBaseChain "filter" "forward" { rules = with rulesCommon; '' @@ -136,16 +144,12 @@ in { '' + conntrack + '' - meta oifname ${nets.lan.interface} accept - meta iifname . meta oifname vmap \ - { ${nets.wan.interface} . ${nets.iot.interface} \ - : goto wan_iot \ - , ${nets.iot.interface} . ${nets.wan.interface} \ - : goto iot_wan \ - , ${nets.wan.interface} . ${nets.eth0.interface} \ - : goto wan_eth0 \ - , ${nets.eth0.interface} . ${nets.wan.interface} \ - : goto eth0_wan } + meta oifname enp4s0 accept + meta iifname . meta oifname vmap \ + { wan . iot : goto wan_iot \ + , iot . wan : goto iot_wan \ + , wan . enp3s0 : goto wan_enp3s0 \ + , enp3s0 . wan : goto enp3s0_wan } ''; }; }; @@ -156,8 +160,8 @@ in { priority = "srcnat"; policy = "accept"; rules = '' - meta oifname ${nets.lan.interface} \ - snat to ${nets.lan.machines.self.ip} + meta oifname enp4s0 \ + snat to ${interfaces.all.enp4s0.machines.self.ip} ''; }; }; @@ -178,10 +182,10 @@ in { chains = { iot_iot.rules = with rulesCommon; '' - ip saddr { ${nets.iot.machines.sonos-move.ip} \ - , ${nets.iot.machines.sonos-play1.ip} } \ - ip daddr { ${nets.iot.machines.sonos-move.ip} \ - , ${nets.iot.machines.sonos-play1.ip} } \ + ip saddr { ${machines.sonos-move.ip} \ + , ${machines.sonos-play1.ip} } \ + ip daddr { ${machines.sonos-move.ip} \ + , ${machines.sonos-play1.ip} } \ accept comment "sonos: player to player" '' + ssdp @@ -197,8 +201,8 @@ in { + ping + '' meta ibrname . meta obrname vmap \ - { ${nets.wan.interface} . ${nets.wan.interface} : goto wan_wan \ - , ${nets.iot.interface} . ${nets.iot.interface} : goto iot_iot } + { wan . wan : goto wan_wan \ + , iot . iot : goto iot_iot } ''; }; }; diff --git a/config/networking/services/ifplugd.nix b/config/networking/services/ifplugd.nix index 4933b97..b904e90 100644 --- a/config/networking/services/ifplugd.nix +++ b/config/networking/services/ifplugd.nix @@ -1,12 +1,8 @@ -{ - config, - pkgs, - ... -}: let - iface = config.personal.networking.networks.eth0.device; +{pkgs, ...}: let + iface = "enp3s0"; dhcpService = "kea-dhcp4-server.service"; action = pkgs.writeShellApplication { - name = "ifplugd-enp3s0.action"; + name = "ifplugd-${iface}.action"; runtimeInputs = [pkgs.systemd]; text = '' INTERFACE="$1" @@ -30,7 +26,7 @@ in { script = '' # iface no-daemon no-auto no-shutdown delay-up run ifplugd -i ${iface} -n -a -q -u 5 -r \ - ${action}/bin/ifplugd-enp3s0.action + ${action}/bin/ifplugd-${iface}.action ''; path = [pkgs.busybox]; }; diff --git a/config/networking/services/igmpproxy.nix b/config/networking/services/igmpproxy.nix index 6999807..d3ac7f3 100644 --- a/config/networking/services/igmpproxy.nix +++ b/config/networking/services/igmpproxy.nix @@ -1,20 +1,25 @@ -{ config, pkgs, ... }: - -let - nets = config.personal.networking.networks; - netdevServices = builtins.map (subnet: "${subnet.interface}-netdev.service") - (with nets; [ wan iot ]); - conf = pkgs.writeText "igmpproxy.conf" '' - phyint ${nets.wan.interface} upstream ratelimit 0 threshold 1 - phyint ${nets.iot.interface} downstream ratelimit 0 threshold 1 - ''; +{ + lib, + pkgs, + ... +}: let + upstream = "wan"; + downstream = ["iot"]; + netdevServices = builtins.map (iface: "${iface}-netdev.service") ([upstream] ++ downstream); + conf = pkgs.writeText "igmpproxy.conf" ('' + phyint ${upstream} upstream ratelimit 0 threshold 1 + '' + + lib.concatMapStrings (iface: '' + phyint ${iface} downstream ratelimit 0 threshold 1 + '') + downstream); in { systemd.services.igmpproxy = { description = "Multicast router utilizing IGMP forwarding"; - wantedBy = [ "multi-user.target" ]; - after = [ "kea-dhcp4-server.service" ] ++ netdevServices; + wantedBy = ["multi-user.target"]; + after = ["kea-dhcp4-server.service"] ++ netdevServices; bindsTo = netdevServices; - path = [ pkgs.igmpproxy ]; + path = [pkgs.igmpproxy]; script = "igmpproxy -v -n ${conf}"; }; } |
