create gateway profile by extracting from rotuer example
This commit is contained in:
parent
0a820a702a
commit
9263b21faa
4 changed files with 235 additions and 151 deletions
|
@ -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];
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,65 +31,64 @@ 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 = {
|
||||||
interface = config.hardware.networkInterfaces.wlan;
|
lan = {
|
||||||
params = {
|
interfaces = with config.hardware.networkInterfaces;
|
||||||
ssid = secrets.ssid;
|
[
|
||||||
hw_mode="g";
|
wlan wlan5
|
||||||
channel = "2";
|
lan0 lan1 lan2 lan3 lan4
|
||||||
ieee80211n = 1;
|
];
|
||||||
} // wirelessConfig;
|
inherit (secrets.lan) prefix;
|
||||||
};
|
address = {
|
||||||
|
family = "inet"; address ="${secrets.lan.prefix}.1"; prefixLength = 24;
|
||||||
services.hostap5 = svc.hostapd.build {
|
};
|
||||||
interface = config.hardware.networkInterfaces.wlan5;
|
dhcp = {
|
||||||
params = rec {
|
start = 10;
|
||||||
ssid = "${secrets.ssid}5";
|
end = 240;
|
||||||
hw_mode="a";
|
hosts = { } // lib.optionalAttrs (builtins.pathExists ./static-leases.nix) (import ./static-leases.nix);
|
||||||
channel = 36;
|
localDomain = "lan";
|
||||||
ht_capab = "[HT40+]";
|
};
|
||||||
vht_oper_chwidth = 1;
|
};
|
||||||
vht_oper_centr_freq_seg0_idx = channel + 6;
|
wan = {
|
||||||
ieee80211n = 1;
|
interface = config.hardware.networkInterfaces.wan;
|
||||||
ieee80211ac = 1;
|
username = secrets.l2tp.name;
|
||||||
} // wirelessConfig;
|
password = secrets.l2tp.password;
|
||||||
};
|
dhcp6.enable = true;
|
||||||
|
};
|
||||||
services.int = svc.network.address.build {
|
firewall = {
|
||||||
interface = svc.bridge.primary.build { ifname = "int"; };
|
enable = true;
|
||||||
family = "inet"; address ="${secrets.lan.prefix}.1"; prefixLength = 24;
|
rules =
|
||||||
};
|
let defaults = import ./demo-firewall.nix;
|
||||||
|
in lib.recursiveUpdate defaults secrets.firewallRules;
|
||||||
services.bridge = svc.bridge.members.build {
|
};
|
||||||
primary = services.int;
|
wireless.networks = {
|
||||||
members = with config.hardware.networkInterfaces;
|
"${secrets.ssid}" = {
|
||||||
[ wlan
|
interface = config.hardware.networkInterfaces.wlan;
|
||||||
wlan5
|
hw_mode="g";
|
||||||
lan0
|
channel = "2";
|
||||||
lan1
|
ieee80211n = 1;
|
||||||
lan2
|
} // wirelessConfig;
|
||||||
lan3
|
"${secrets.ssid}5" = rec {
|
||||||
lan4
|
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 {
|
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
|
||||||
|
|
178
modules/profiles/gateway.nix
Normal file
178
modules/profiles/gateway.nix
Normal 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";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -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";
|
||||||
|
|
Loading…
Reference in a new issue