214 lines
6.6 KiB
Nix
214 lines
6.6 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
namespace,
|
|
...
|
|
}:
|
|
with lib;
|
|
let
|
|
cfg = config.${namespace}.network;
|
|
|
|
profiles =
|
|
let
|
|
make =
|
|
name: profile:
|
|
nameValuePair "${name}" {
|
|
connection = {
|
|
inherit (profile) type autoconnect autoconnect-retries;
|
|
id = name;
|
|
autoconnect-priority = profile.priority;
|
|
interface-name = profile.interface or cfg.ipv4.interface;
|
|
};
|
|
ipv4 = {
|
|
inherit (cfg.ipv4) method;
|
|
}
|
|
// (
|
|
if (cfg.ipv4.method == "auto") then
|
|
{ }
|
|
else
|
|
{
|
|
inherit (cfg.ipv4) address gateway dns;
|
|
}
|
|
);
|
|
ipv6 = {
|
|
addr-gen-mode = "stable-privacy";
|
|
method = "auto";
|
|
};
|
|
wifi = mkIf (profile.type == "wifi") {
|
|
inherit (profile) ssid;
|
|
mode = "infrastructure";
|
|
roaming = "allowed";
|
|
};
|
|
wifi-security = mkIf (profile.type == "wifi") {
|
|
inherit (profile) psk;
|
|
key-mgmt = profile.keyMgmt;
|
|
};
|
|
};
|
|
|
|
userProfiles = mapAttrs' make cfg.networkmanager.profiles;
|
|
|
|
# When using manual IP with NM enabled, auto-generate an ethernet profile
|
|
# so NM actually assigns the static address (not just DHCP).
|
|
ethernetProfile =
|
|
optionalAttrs (cfg.ipv4.method == "manual" && cfg.ipv4.interface != "" && cfg.networkmanager.enable)
|
|
{
|
|
"static-${cfg.ipv4.interface}" = {
|
|
connection = {
|
|
id = "static-${cfg.ipv4.interface}";
|
|
type = "ethernet";
|
|
autoconnect = true;
|
|
interface-name = cfg.ipv4.interface;
|
|
};
|
|
ipv4 = {
|
|
inherit (cfg.ipv4) address gateway dns;
|
|
method = "manual";
|
|
};
|
|
ipv6 = {
|
|
addr-gen-mode = "stable-privacy";
|
|
method = "auto";
|
|
};
|
|
};
|
|
};
|
|
in
|
|
userProfiles // ethernetProfile;
|
|
in
|
|
{
|
|
imports = [
|
|
./options.nix
|
|
];
|
|
|
|
config = {
|
|
assertions = [
|
|
{
|
|
assertion = cfg.hostName != "";
|
|
message = "mjallen.network.hostName must be set to a non-empty string.";
|
|
}
|
|
{
|
|
assertion = cfg.ipv4.method == "auto" || cfg.ipv4.method == "manual";
|
|
message = "mjallen.network.ipv4.method must be either \"auto\" or \"manual\" (got \"${cfg.ipv4.method}\").";
|
|
}
|
|
{
|
|
assertion = cfg.ipv4.method != "manual" || cfg.ipv4.interface != "";
|
|
message = "mjallen.network.ipv4.interface must be set when ipv4.method is \"manual\".";
|
|
}
|
|
{
|
|
assertion = cfg.ipv4.method != "manual" || cfg.ipv4.address != "";
|
|
message = "mjallen.network.ipv4.address must be set when ipv4.method is \"manual\".";
|
|
}
|
|
{
|
|
assertion = cfg.ipv4.method != "manual" || cfg.ipv4.gateway != "";
|
|
message = "mjallen.network.ipv4.gateway must be set when ipv4.method is \"manual\".";
|
|
}
|
|
{
|
|
assertion = cfg.nat.enable -> cfg.nat.externalInterface != "";
|
|
message = "mjallen.network.nat.externalInterface must be set when NAT is enabled.";
|
|
}
|
|
];
|
|
|
|
systemd = {
|
|
services = {
|
|
NetworkManager-wait-online.enable = false;
|
|
systemd-networkd-wait-online.enable = lib.mkForce false;
|
|
systemd-networkd.stopIfChanged = false;
|
|
systemd-resolved.stopIfChanged = false;
|
|
};
|
|
network.wait-online.enable = false;
|
|
};
|
|
|
|
# Restrict Avahi to the configured LAN interface when one is explicitly set.
|
|
# This prevents Avahi from announcing on virtual/container interfaces (veth*,
|
|
# podman0, virbr0, etc.) which causes hostname conflicts and suffix mangling
|
|
# (e.g. "jallen-nas-4.local" instead of "jallen-nas.local").
|
|
services.avahi = lib.mkIf (cfg.ipv4.interface != "") {
|
|
allowInterfaces = [ cfg.ipv4.interface ];
|
|
};
|
|
|
|
networking = {
|
|
hostName = lib.mkForce cfg.hostName;
|
|
|
|
# Use networkd if enabled
|
|
useNetworkd = lib.mkDefault true;
|
|
|
|
# Set default gateway and nameservers if in manual mode
|
|
defaultGateway = lib.mkIf (cfg.ipv4.method == "manual") {
|
|
address = cfg.ipv4.gateway;
|
|
interface = lib.mkIf (cfg.ipv4.interface != "") cfg.ipv4.interface;
|
|
};
|
|
|
|
nameservers = lib.mkIf (cfg.ipv4.method == "manual") [ cfg.ipv4.dns ];
|
|
|
|
# Set hostId if provided
|
|
hostId = lib.mkIf (cfg.hostId != "") cfg.hostId;
|
|
|
|
# Configure NAT if enabled
|
|
nat = lib.mkIf cfg.nat.enable {
|
|
inherit (cfg.nat) internalInterfaces externalInterface enableIPv6;
|
|
enable = true;
|
|
};
|
|
|
|
# Configure firewall
|
|
firewall = {
|
|
inherit (cfg.firewall)
|
|
enable
|
|
allowPing
|
|
allowedTCPPorts
|
|
allowedUDPPorts
|
|
trustedInterfaces
|
|
;
|
|
|
|
# Default port ranges for KDE Connect
|
|
allowedTCPPortRanges = lib.mkIf cfg.firewall.kdeConnect.enable [
|
|
{
|
|
inherit (cfg.firewall.kdeConnect.tcpRange) from to;
|
|
}
|
|
];
|
|
allowedUDPPortRanges = lib.mkIf cfg.firewall.kdeConnect.enable [
|
|
{
|
|
inherit (cfg.firewall.kdeConnect.udpRange) from to;
|
|
}
|
|
];
|
|
|
|
# Extra firewall commands
|
|
extraCommands = lib.mkIf (cfg.extraFirewallCommands != "") cfg.extraFirewallCommands;
|
|
};
|
|
|
|
# Enable iwd daemon when requested.
|
|
# When iwd is enabled alongside NetworkManager, iwd acts as the WiFi
|
|
# backend for NM (iwd handles scanning/association; NM handles
|
|
# connection management). They are not mutually exclusive.
|
|
wireless.iwd = {
|
|
inherit (cfg.iwd)
|
|
enable
|
|
settings
|
|
;
|
|
};
|
|
|
|
# Configure NetworkManager when enabled
|
|
networkmanager = {
|
|
inherit (cfg.networkmanager) enable;
|
|
# Use iwd as the WiFi backend when iwd is also enabled
|
|
wifi.backend = mkIf cfg.iwd.enable "iwd";
|
|
wifi.powersave = cfg.networkmanager.powersave;
|
|
settings.connectivity.uri = "http://nmcheck.gnome.org/check_network_status.txt";
|
|
plugins = with pkgs; [
|
|
networkmanager-fortisslvpn
|
|
networkmanager-iodine
|
|
networkmanager-l2tp
|
|
networkmanager-openconnect
|
|
networkmanager-openvpn
|
|
networkmanager-sstp
|
|
networkmanager-strongswan
|
|
networkmanager-vpnc
|
|
];
|
|
|
|
# Configure profiles if any are defined
|
|
ensureProfiles = mkIf (profiles != { }) {
|
|
environmentFiles = lib.optional (config.sops.secrets ? wifi) config.sops.secrets.wifi.path;
|
|
inherit profiles;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
}
|