From 9263b21faa487abdfd89cd590c1c870d34640a0a Mon Sep 17 00:00:00 2001 From: Daniel Barlow Date: Mon, 18 Mar 2024 00:05:43 +0000 Subject: [PATCH] create gateway profile by extracting from rotuer example --- examples/extneder.nix | 3 + examples/rotuer.nix | 203 ++++++++++------------------------- modules/profiles/gateway.nix | 178 ++++++++++++++++++++++++++++++ modules/profiles/wap.nix | 2 - 4 files changed, 235 insertions(+), 151 deletions(-) create mode 100644 modules/profiles/gateway.nix diff --git a/examples/extneder.nix b/examples/extneder.nix index 2aa777d..7156f70 100644 --- a/examples/extneder.nix +++ b/examples/extneder.nix @@ -12,6 +12,7 @@ ... }: let secrets = import ./extneder-secrets.nix; + svc = config.system.service; in rec { boot = { tftp = { @@ -23,6 +24,7 @@ in rec { imports = [ "${modulesPath}/profiles/wap.nix" "${modulesPath}/vlan" + "${modulesPath}/ssh" ]; hostname = "extneder"; @@ -45,6 +47,7 @@ in rec { }; }; + services.sshd = svc.ssh.build {}; users.root.passwd = lib.mkForce secrets.root.passwd; defaultProfile.packages = with pkgs; [nftables strace tcpdump swconfig]; } diff --git a/examples/rotuer.nix b/examples/rotuer.nix index f6f9a73..705b888 100644 --- a/examples/rotuer.nix +++ b/examples/rotuer.nix @@ -6,23 +6,18 @@ # problems. -{ config, pkgs, lib, ... } : +{ config, pkgs, lib, modulesPath, ... } : let secrets = { domainName = "fake.liminix.org"; firewallRules = {}; } // (import ./rotuer-secrets.nix); - inherit (pkgs.liminix.services) oneshot longrun bundle; + inherit (pkgs.liminix.services) oneshot bundle; inherit (pkgs) serviceFns; svc = config.system.service; wirelessConfig = { country_code = "GB"; inherit (secrets) wpa_passphrase; - auth_algs = 1; # 1=wpa2, 2=wep, 3=both - wpa = 2; # 1=wpa, 2=wpa2, 3=both - wpa_key_mgmt = "WPA-PSK"; - wpa_pairwise = "TKIP CCMP"; # auth for wpa (may not need this?) - rsn_pairwise = "CCMP"; # auth for wpa2 wmm_enabled = 1; }; @@ -36,65 +31,64 @@ in rec { }; imports = [ - ../modules/wlan.nix - ../modules/network - ../modules/ppp - ../modules/dnsmasq - ../modules/dhcp6c - ../modules/firewall - ../modules/hostapd - ../modules/bridge - ../modules/ntp - ../modules/schnapps - ../modules/ssh - ../modules/outputs/btrfs.nix - ../modules/outputs/extlinux.nix + "${modulesPath}/profiles/gateway.nix" + "${modulesPath}/schnapps" + "${modulesPath}/outputs/btrfs.nix" + "${modulesPath}/outputs/extlinux.nix" ]; hostname = "rotuer"; rootfsType = "btrfs"; rootOptions = "subvol=@"; boot.loader.extlinux.enable = true; - services.hostap = svc.hostapd.build { - interface = config.hardware.networkInterfaces.wlan; - params = { - ssid = secrets.ssid; - hw_mode="g"; - channel = "2"; - ieee80211n = 1; - } // wirelessConfig; - }; - - services.hostap5 = svc.hostapd.build { - interface = config.hardware.networkInterfaces.wlan5; - params = rec { - ssid = "${secrets.ssid}5"; - hw_mode="a"; - channel = 36; - ht_capab = "[HT40+]"; - vht_oper_chwidth = 1; - vht_oper_centr_freq_seg0_idx = channel + 6; - ieee80211n = 1; - ieee80211ac = 1; - } // wirelessConfig; - }; - - services.int = svc.network.address.build { - interface = svc.bridge.primary.build { ifname = "int"; }; - family = "inet"; address ="${secrets.lan.prefix}.1"; prefixLength = 24; - }; - - services.bridge = svc.bridge.members.build { - primary = services.int; - members = with config.hardware.networkInterfaces; - [ wlan - wlan5 - lan0 - lan1 - lan2 - lan3 - lan4 - ]; + profile.gateway = { + lan = { + interfaces = with config.hardware.networkInterfaces; + [ + wlan wlan5 + lan0 lan1 lan2 lan3 lan4 + ]; + inherit (secrets.lan) prefix; + address = { + family = "inet"; address ="${secrets.lan.prefix}.1"; prefixLength = 24; + }; + dhcp = { + start = 10; + end = 240; + hosts = { } // lib.optionalAttrs (builtins.pathExists ./static-leases.nix) (import ./static-leases.nix); + localDomain = "lan"; + }; + }; + wan = { + interface = config.hardware.networkInterfaces.wan; + username = secrets.l2tp.name; + password = secrets.l2tp.password; + dhcp6.enable = true; + }; + firewall = { + enable = true; + rules = + let defaults = import ./demo-firewall.nix; + in lib.recursiveUpdate defaults secrets.firewallRules; + }; + wireless.networks = { + "${secrets.ssid}" = { + interface = config.hardware.networkInterfaces.wlan; + hw_mode="g"; + channel = "2"; + ieee80211n = 1; + } // wirelessConfig; + "${secrets.ssid}5" = rec { + interface = config.hardware.networkInterfaces.wlan5; + hw_mode="a"; + channel = 36; + ht_capab = "[HT40+]"; + vht_oper_chwidth = 1; + vht_oper_centr_freq_seg0_idx = channel + 6; + ieee80211n = 1; + ieee80211ac = 1; + } // wirelessConfig; + }; }; services.ntp = svc.ntp.build { @@ -106,95 +100,6 @@ in rec { users.root = secrets.root; - services.dns = - let interface = services.int; - in svc.dnsmasq.build { - resolvconf = services.resolvconf; - inherit interface; - ranges = [ - "${secrets.lan.prefix}.10,${secrets.lan.prefix}.240" - # ra-stateless: sends router advertisements with the O and A - # bits set, and provides a stateless DHCP service. The client - # will use a SLAAC address, and use DHCP for other - # configuration information. - "::,constructor:$(output ${interface} ifname),ra-stateless" - ]; - - # You can add static addresses for the DHCP server here. I'm - # not putting my actual MAC addresses in a public git repo ... - hosts = { } // lib.optionalAttrs (builtins.pathExists ./static-leases.nix) (import ./static-leases.nix); - upstreams = [ "/${secrets.domainName}/" ]; - domain = secrets.domainName; - }; - - services.wan = svc.pppoe.build { - interface = config.hardware.networkInterfaces.wan; - ppp-options = [ - "debug" "+ipv6" "noauth" - "name" secrets.l2tp.name - "password" secrets.l2tp.password - ]; - }; - - services.resolvconf = oneshot rec { - dependencies = [ services.wan ]; - name = "resolvconf"; - up = '' - . ${serviceFns} - ( in_outputs ${name} - echo "nameserver $(output ${services.wan} ns1)" > resolv.conf - echo "nameserver $(output ${services.wan} ns2)" >> resolv.conf - chmod 0444 resolv.conf - ) - ''; - }; - - filesystem = - let inherit (pkgs.pseudofile) dir symlink; - in dir { - etc = dir { - "resolv.conf" = symlink "${services.resolvconf}/.outputs/resolv.conf"; - }; - }; - - services.defaultroute4 = svc.network.route.build { - via = "$(output ${services.wan} address)"; - target = "default"; - dependencies = [ services.wan ]; - }; - - services.defaultroute6 = svc.network.route.build { - via = "$(output ${services.wan} ipv6-peer-address)"; - target = "default"; - interface = services.wan; - }; - - services.firewall = svc.firewall.build { - ruleset = - let defaults = import ./demo-firewall.nix; - in lib.recursiveUpdate defaults secrets.firewallRules; - }; - - services.packet_forwarding = svc.network.forward.build { }; - - services.dhcp6c = - let client = svc.dhcp6c.client.build { - interface = services.wan; - }; - in bundle { - name = "dhcp6c"; - contents = [ - (svc.dhcp6c.prefix.build { - inherit client; - interface = services.int; - }) - (svc.dhcp6c.address.build { - inherit client; - interface = services.wan; - }) - ]; - }; - defaultProfile.packages = with pkgs; [ min-collect-garbage nftables diff --git a/modules/profiles/gateway.nix b/modules/profiles/gateway.nix new file mode 100644 index 0000000..d97d881 --- /dev/null +++ b/modules/profiles/gateway.nix @@ -0,0 +1,178 @@ +{ config, pkgs, lib, ... } : +let + svc = config.system.service; + cfg = config.profile.gateway; + inherit (lib) mkOption mkEnableOption mkIf mdDoc types optional optionals; + inherit (pkgs) liminix serviceFns; + inherit (liminix.services) bundle oneshot; + hostaps = + let + defaults = { + auth_algs = 1; # 1=wpa2, 2=wep, 3=both + wpa = 2; # 1=wpa, 2=wpa2, 3=both + wpa_key_mgmt = "WPA-PSK"; + wpa_pairwise = "TKIP CCMP"; # auth for wpa (may not need this?) + rsn_pairwise = "CCMP"; # auth for wpa2 + }; + in lib.mapAttrs' + (name : value : + let + attrs = defaults // { ssid = name; } // value; + in lib.nameValuePair + "hostap-${name}" + (svc.hostapd.build { + interface = attrs.interface; + params = lib.filterAttrs (k: v: k != "interface") attrs; + })) + cfg.wireless.networks; +in { + + options.profile.gateway = { + lan = { + interfaces = mkOption { + type = types.listOf liminix.lib.types.interface; + default = []; + }; + address = mkOption { + type = types.attrs; + }; + prefix = mkOption { type = types.str; }; + dhcp = { + start = mkOption { type = types.int; }; + end = mkOption { type = types.int; }; + hosts = mkOption { type = types.attrs; }; + localDomain = mkOption { type = types.str; }; + }; + }; + + firewall = { + enable = mkEnableOption "firewall"; + rules = mkOption { type = types.attrsOf types.attrs; }; + }; + + wan = { + interface = mkOption { type = liminix.lib.types.interface; }; + username = mkOption { type = types.str; }; + password = mkOption { type = types.str; }; + dhcp6.enable = mkOption { type = types.bool; }; + }; + + wireless = mkOption { + type = types.attrsOf types.anything; + }; + }; + + imports = [ + ../wlan.nix + ../network + ../ppp + ../dnsmasq + ../dhcp6c + ../firewall + ../hostapd + ../bridge + ../ntp + ../ssh + { config.services = hostaps; } + ]; + + config = { + services.int = svc.network.address.build ({ + interface = svc.bridge.primary.build { ifname = "int"; }; + } // cfg.lan.address); + + services.bridge = svc.bridge.members.build { + primary = config.services.int; + members = cfg.lan.interfaces; + }; + + services.wan = svc.pppoe.build { + inherit (cfg.wan) interface; + ppp-options = [ + "debug" "+ipv6" "noauth" + "name" cfg.wan.username + "password" cfg.wan.password + ]; + }; + + services.packet_forwarding = svc.network.forward.build { }; + + services.dhcp6c = + let + client = svc.dhcp6c.client.build { + interface = config.services.wan; + }; + bundl = bundle { + name = "dhcp6c"; + contents = [ + (svc.dhcp6c.prefix.build { + inherit client; + interface = config.services.int; + }) + (svc.dhcp6c.address.build { + inherit client; + interface = config.services.wan; + }) + ]; + }; + in mkIf cfg.wan.dhcp6.enable bundl; + + services.dns = + let interface = config.services.int; + dcfg = cfg.lan.dhcp; + in svc.dnsmasq.build { + resolvconf = config.services.resolvconf; + inherit interface; + ranges = [ + "${cfg.lan.prefix}.${toString dcfg.start},${cfg.lan.prefix}.${toString dcfg.end}" + # ra-stateless: sends router advertisements with the O and A + # bits set, and provides a stateless DHCP service. The client + # will use a SLAAC address, and use DHCP for other + # configuration information. + "::,constructor:$(output ${interface} ifname),ra-stateless" + ]; + + hosts = dcfg.hosts; + upstreams = [ "/${dcfg.localDomain}/" ]; + domain = dcfg.localDomain; + }; + + services.defaultroute4 = svc.network.route.build { + via = "$(output ${config.services.wan} address)"; + target = "default"; + dependencies = [ config.services.wan ]; + }; + + services.defaultroute6 = svc.network.route.build { + via = "$(output ${config.services.wan} ipv6-peer-address)"; + target = "default"; + interface = config.services.wan; + }; + + services.firewall = mkIf cfg.firewall.enable + (svc.firewall.build { + ruleset = cfg.firewall.rules; + }); + + services.resolvconf = oneshot rec { + dependencies = [ config.services.wan ]; + name = "resolvconf"; + up = '' + . ${serviceFns} + ( in_outputs ${name} + echo "nameserver $(output ${config.services.wan} ns1)" > resolv.conf + echo "nameserver $(output ${config.services.wan} ns2)" >> resolv.conf + chmod 0444 resolv.conf + ) + ''; + }; + + filesystem = + let inherit (pkgs.pseudofile) dir symlink; + in dir { + etc = dir { + "resolv.conf" = symlink "${config.services.resolvconf}/.outputs/resolv.conf"; + }; + }; + }; + } diff --git a/modules/profiles/wap.nix b/modules/profiles/wap.nix index 5c95e99..fdb3b41 100644 --- a/modules/profiles/wap.nix +++ b/modules/profiles/wap.nix @@ -40,7 +40,6 @@ in { ../network ../hostapd ../bridge - ../ssh { config.services = hostaps; } ]; @@ -54,7 +53,6 @@ in { }; }; config = { - services.sshd = svc.ssh.build {}; services.int = svc.bridge.primary.build { ifname = "int";