summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorquentin@aristote.fr <quentin@aristote.fr>2024-09-29 19:56:08 +0200
committerquentin@aristote.fr <quentin@aristote.fr>2024-10-27 19:08:46 +0100
commit491c4bf6b4596b486b12724e9124a854cc7abc26 (patch)
tree3911453e589959da652a1d5f62e5966b05f1643e
parent072ad00164e98823691e7da1cdd07ac368391c38 (diff)
migrate hostapd config
-rw-r--r--config/default.nix4
-rw-r--r--config/networking/bridges.nix47
-rw-r--r--config/networking/default.nix202
-rw-r--r--config/networking/services/ap.nix277
-rw-r--r--config/networking/services/dhcp.nix36
-rw-r--r--config/networking/services/dns.nix35
-rw-r--r--config/networking/services/firewall/default.nix80
-rw-r--r--config/networking/services/firewall/ruleset.nix68
-rw-r--r--config/networking/services/ifplugd.nix12
-rw-r--r--config/networking/services/igmpproxy.nix31
-rw-r--r--flake.nix1
-rw-r--r--secrets.nix10
12 files changed, 387 insertions, 416 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}";
};
}
diff --git a/flake.nix b/flake.nix
index f349091..1c95cbc 100644
--- a/flake.nix
+++ b/flake.nix
@@ -22,7 +22,6 @@
modules = commonModules ++ [./config];
specialArgs = {
inherit nixos-hardware;
- secrets = import ./secrets.nix;
};
};
};
diff --git a/secrets.nix b/secrets.nix
deleted file mode 100644
index a49baee..0000000
--- a/secrets.nix
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- wifi = {
- iot = {
- passphrase = builtins.readFile "/etc/hostapd/hostapd.iot.pw";
- };
- wan = {
- passphrase = builtins.readFile "/etc/hostapd/hostapd.wan.pw";
- };
- };
-}