create gateway profile by extracting from rotuer example

This commit is contained in:
Daniel Barlow 2024-03-18 00:05:43 +00:00
parent 0a820a702a
commit 9263b21faa
4 changed files with 235 additions and 151 deletions

View file

@ -12,6 +12,7 @@
... ...
}: let }: let
secrets = import ./extneder-secrets.nix; secrets = import ./extneder-secrets.nix;
svc = config.system.service;
in rec { in rec {
boot = { boot = {
tftp = { tftp = {
@ -23,6 +24,7 @@ in rec {
imports = [ imports = [
"${modulesPath}/profiles/wap.nix" "${modulesPath}/profiles/wap.nix"
"${modulesPath}/vlan" "${modulesPath}/vlan"
"${modulesPath}/ssh"
]; ];
hostname = "extneder"; hostname = "extneder";
@ -45,6 +47,7 @@ in rec {
}; };
}; };
services.sshd = svc.ssh.build {};
users.root.passwd = lib.mkForce secrets.root.passwd; users.root.passwd = lib.mkForce secrets.root.passwd;
defaultProfile.packages = with pkgs; [nftables strace tcpdump swconfig]; defaultProfile.packages = with pkgs; [nftables strace tcpdump swconfig];
} }

View file

@ -6,23 +6,18 @@
# problems. # problems.
{ config, pkgs, lib, ... } : { config, pkgs, lib, modulesPath, ... } :
let let
secrets = { secrets = {
domainName = "fake.liminix.org"; domainName = "fake.liminix.org";
firewallRules = {}; firewallRules = {};
} // (import ./rotuer-secrets.nix); } // (import ./rotuer-secrets.nix);
inherit (pkgs.liminix.services) oneshot longrun bundle; inherit (pkgs.liminix.services) oneshot bundle;
inherit (pkgs) serviceFns; inherit (pkgs) serviceFns;
svc = config.system.service; svc = config.system.service;
wirelessConfig = { wirelessConfig = {
country_code = "GB"; country_code = "GB";
inherit (secrets) wpa_passphrase; 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; wmm_enabled = 1;
}; };
@ -36,39 +31,55 @@ in rec {
}; };
imports = [ imports = [
../modules/wlan.nix "${modulesPath}/profiles/gateway.nix"
../modules/network "${modulesPath}/schnapps"
../modules/ppp "${modulesPath}/outputs/btrfs.nix"
../modules/dnsmasq "${modulesPath}/outputs/extlinux.nix"
../modules/dhcp6c
../modules/firewall
../modules/hostapd
../modules/bridge
../modules/ntp
../modules/schnapps
../modules/ssh
../modules/outputs/btrfs.nix
../modules/outputs/extlinux.nix
]; ];
hostname = "rotuer"; hostname = "rotuer";
rootfsType = "btrfs"; rootfsType = "btrfs";
rootOptions = "subvol=@"; rootOptions = "subvol=@";
boot.loader.extlinux.enable = true; boot.loader.extlinux.enable = true;
services.hostap = svc.hostapd.build { 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; interface = config.hardware.networkInterfaces.wlan;
params = {
ssid = secrets.ssid;
hw_mode="g"; hw_mode="g";
channel = "2"; channel = "2";
ieee80211n = 1; ieee80211n = 1;
} // wirelessConfig; } // wirelessConfig;
}; "${secrets.ssid}5" = rec {
services.hostap5 = svc.hostapd.build {
interface = config.hardware.networkInterfaces.wlan5; interface = config.hardware.networkInterfaces.wlan5;
params = rec {
ssid = "${secrets.ssid}5";
hw_mode="a"; hw_mode="a";
channel = 36; channel = 36;
ht_capab = "[HT40+]"; ht_capab = "[HT40+]";
@ -78,23 +89,6 @@ in rec {
ieee80211ac = 1; ieee80211ac = 1;
} // wirelessConfig; } // 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
];
}; };
services.ntp = svc.ntp.build { services.ntp = svc.ntp.build {
@ -106,95 +100,6 @@ in rec {
users.root = secrets.root; 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; [ defaultProfile.packages = with pkgs; [
min-collect-garbage min-collect-garbage
nftables nftables

View file

@ -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";
};
};
};
}

View file

@ -40,7 +40,6 @@ in {
../network ../network
../hostapd ../hostapd
../bridge ../bridge
../ssh
{ config.services = hostaps; } { config.services = hostaps; }
]; ];
@ -54,7 +53,6 @@ in {
}; };
}; };
config = { config = {
services.sshd = svc.ssh.build {};
services.int = svc.bridge.primary.build { services.int = svc.bridge.primary.build {
ifname = "int"; ifname = "int";