- zones are an attrset of name -> [interface-service] - the firewall will create empty "ifname" sets for each zone name in each address family (ip, ip6) - then watch the interface services, and add the "ifname" outputs to the corresponding sets when they appear This commit only adds the empty sets
173 lines
4.7 KiB
Nix
173 lines
4.7 KiB
Nix
{ config, pkgs, lib, ... } :
|
|
let
|
|
svc = config.system.service;
|
|
cfg = config.profile.gateway;
|
|
inherit (lib) mkOption mkEnableOption mkIf types;
|
|
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; };
|
|
zones = mkOption {
|
|
type = types.attrsOf (types.listOf liminix.lib.types.service);
|
|
};
|
|
};
|
|
|
|
wan = {
|
|
interface = mkOption { type = liminix.lib.types.interface; };
|
|
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 = cfg.wan.interface;
|
|
|
|
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 {
|
|
extraRules = cfg.firewall.rules;
|
|
inherit (cfg.firewall) zones;
|
|
});
|
|
|
|
services.resolvconf = oneshot rec {
|
|
dependencies = [ config.services.wan ];
|
|
name = "resolvconf";
|
|
up = ''
|
|
( 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";
|
|
};
|
|
};
|
|
};
|
|
}
|