You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

202 lines
6.4 KiB
Nix

{ pkgs, config, lib, ... }:
with lib;
let
cfg = config.ffnix;
activeDomains = attrsets.filterAttrs (n: v: v.enable) cfg.domains;
mkDomain = name: domCfg:
let
cidrToAddress = cidr: head (splitString "/" cidr);
mkIfName = type: substring 0 15 (
if type == "bridge" then "br-${name}" else
if type == "batman" then "bat-${name}" else
if type == "fastd" then "fd-${name}" else
throw "unknown interface type ${type}, coud not generate name"
);
in {
#### NULL-ROUTES ####
networks."10-lo" = {
routes = if !domCfg.defaultNullRoute then [] else [
{
routeConfig = {
Destination = "0.0.0.0/0";
Metric = 200;
Type = "unreachable";
Table = domCfg.routingTable;
};
}
{
routeConfig = {
Destination = "::/0";
Metric = 200;
Type = "unreachable";
Table = domCfg.routingTable;
};
}
];
};
#### BRIDGE ####
netdevs."30-${mkIfName "bridge"}".netdevConfig = {
Name = mkIfName "bridge";
Kind = "bridge";
};
networks."30-${mkIfName "bridge"}" = {
matchConfig.Name = mkIfName "bridge";
linkConfig = {
RequiredForOnline = "no";
MTUBytes = "${toString domCfg.mtu}";
};
address = domCfg.ipv4Addresses ++ domCfg.ipv6Addresses;
routes = map (prefix: {
routeConfig = {
Destination = prefix;
Scope = "link";
Table = domCfg.routingTable;
};
}) (domCfg.ipv6Prefixes ++ [ domCfg.ipv4Prefix ]);
routingPolicyRules = [
{
routingPolicyRuleConfig = {
IncomingInterface = mkIfName "bridge";
Table = domCfg.routingTable;
Family = "both";
};
}
] ++ map (prefix: {
routingPolicyRuleConfig = {
From = prefix;
Table = domCfg.routingTable;
};
}) (domCfg.ipv6Prefixes ++ [ domCfg.ipv4Prefix ]);
};
#### BATMAN ####
netdevs."30-${mkIfName "batman"}" = mkIf (!cfg.batmanLegacy) {
netdevConfig = {
Kind = "batadv";
Name = mkIfName "batman";
};
batmanAdvancedConfig = {
GatewayMode = "server";
RoutingAlgorithm = domCfg.batmanAlgorithm;
OriginatorIntervalSec = 5;
};
};
networks."30-${mkIfName "batman"}" = {
matchConfig.Name = mkIfName "batman";
bridge = [ "${mkIfName "bridge"}" ];
};
#### FASTD ####
fdInstances."${mkIfName "fastd"}" = mkIf domCfg.tunnels.fastd.enable ({
bind = mkDefault [ "any:${toString domCfg.tunnels.fastd.port}" ];
mtu = domCfg.tunnels.fastd.mtu;
} // domCfg.tunnels.fastd.extraConfig);
links."30-${mkIfName "fastd"}" = mkIf domCfg.tunnels.fastd.enable {
matchConfig.OriginalName = mkIfName "fastd";
linkConfig.MACAddress = domCfg.tunnels.fastd.interfaceMac;
};
networks."30-${mkIfName "fastd"}" = mkIf (domCfg.tunnels.fastd.enable && !cfg.batmanLegacy) {
matchConfig.Name = mkIfName "fastd";
networkConfig.BatmanAdvanced = mkIfName "batman";
};
services."${mkIfName "batman"}" = mkIf (domCfg.tunnels.fastd.enable && cfg.batmanLegacy) {
after = [ "fastd-${mkIfName "fastd"}.service" ];
requiredBy = [ "fastd-${mkIfName "fastd"}.service" ];
script = ''
timeout 30 ${pkgs.bash}/bin/sh -c 'while ! ${pkgs.iproute2}/bin/ip link show dev ${mkIfName "fastd"} | grep -e UNKNOWN -e DOWN ; do sleep 1; done'
${pkgs.batctl-legacy}/bin/batctl -m ${mkIfName "batman"} interface add ${mkIfName "fastd"} || true
${pkgs.batctl-legacy}/bin/batctl -m ${mkIfName "batman"} gw_mode server || true
'';
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
};
#### KEA / DHCPv4 ####
keaInterfaces = if (domCfg.dhcpRange == "") then [] else [ "${mkIfName "bridge"}" ];
keaSubnet4 = mkIf (domCfg.dhcpRange != "") ([ ({
subnet = domCfg.ipv4Prefix;
pools = [
{
pool = domCfg.dhcpRange;
}
];
option-data = [
{
name = "routers";
data = cidrToAddress (head domCfg.ipv4Addresses);
}
{
name = "domain-name-servers";
data = cidrToAddress (head domCfg.ipv4Addresses);
}
{
name = "domain-name";
data = domCfg.searchDomain;
}
];
} // domCfg.dhcpExtraConfig) ]);
#### RADVD ####
radvdConfig = let
radvdPrefixes = if domCfg.radvdPrefixes == [] then domCfg.ipv6Prefixes else domCfg.radvdPrefixes;
mkPrefix = prefix: ''
prefix ${prefix} {
AdvOnLink on;
AdvAutonomous on;
AdvRouterAddr on;
};
'';
in if (!domCfg.enableRadvd) then [] else [ ''
interface ${mkIfName "bridge"} {
IgnoreIfMissing on;
AdvSendAdvert on;
MinRtrAdvInterval 3;
MaxRtrAdvInterval 10;
AdvLinkMTU ${toString domCfg.mtu};
RDNSS ${cidrToAddress (head domCfg.ipv6Addresses)} { };
DNSSL ${domCfg.searchDomain} { };
${concatStringsSep "\n" (map mkPrefix radvdPrefixes)}
};
'' ];
};
domConfigs = map (key: getAttr key (mapAttrs mkDomain activeDomains)) (attrNames activeDomains);
mergedConfigs = mapAttrs (name: value: mkMerge value) (attrsets.zipAttrs (map (x: removeAttrs x [ ]) domConfigs));
in
{
config = mkIf cfg.enable {
systemd.network.netdevs = mergedConfigs.netdevs;
systemd.network.networks = mergedConfigs.networks;
systemd.network.links = mergedConfigs.links;
systemd.services = mergedConfigs.services;
ffnix.fastd.instances = mergedConfigs.fdInstances;
services.kea.dhcp4 = mkIf (concatLists mergedConfigs.keaInterfaces.contents != []) {
enable = true;
settings = {
interfaces-config = {
interfaces = mergedConfigs.keaInterfaces;
};
subnet4 = mergedConfigs.keaSubnet4;
};
};
services.radvd = mkIf (concatLists mergedConfigs.radvdConfig.contents != []) {
enable = true;
config = concatStringsSep "\n" (concatLists mergedConfigs.radvdConfig.contents);
};
};
}