# xlab-gateway - Lab Gateway / Router
# TODO: Migrate from Debian 12 to NixOS
# Current services: Kea DHCP4/6, DDNS, radvd, WireGuard, NAT, policy routing
{ config, pkgs, lib, ... }:
{
imports = [
./hardware-configuration.nix
./networking.nix
./dhcp.nix
];
age.identityPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
networking.hostName = "xlab-gateway";
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
boot = {
loader = {
systemd-boot.enable = true;
efi.canTouchEfiVariables = true;
};
kernel.sysctl = {
"net.ipv4.ip_forward" = 1;
"net.ipv6.conf.all.forwarding" = 1;
};
};
# Gateway doesn't need to block boot waiting for all interfaces
systemd.network.wait-online.enable = false;
users.users.ldx = {
extraGroups = [ "networkmanager" ];
hashedPassword = "$y$j9T$R0XBoDSGk700h7UdglfaJ1$mjRwpJir/Tno1.fCbjet0cp/JPb1DW.JILvmE5.NJuD";
};
users.users."ye-lw21" = {
extraGroups = [ "networkmanager" ];
hashedPassword = "$y$j9T$jiLKGLB/gJKEYYn2zaoUw/$9mfwEUo5z2sH9OXwioLnbAVpCMOg2lUpA3ph9Vqx228";
};
environment.systemPackages = with pkgs; [
wireguard-tools
iperf3
ethtool
tcpdump
nftables
iproute2
glances
smartmontools
];
services.smartd = {
enable = true;
autodetect = true;
};
# CAPWAP over the 1420-MTU wg-to-wgnet tunnel: the lab Cisco APs (e.g. 3802
# b08b.cfa8.4fa8) send ~1469B DON'T-FRAGMENT DTLS packets to the C9800 WLC at
# 10.0.10.10 during join, and ignore both PMTUD and DHCP interface-mtu, so the
# CAPWAP/DTLS handshake blackholes on the tunnel and the AP never joins. Clear
# the DF bit on UDP->WLC at ingress so those packets fragment through the tunnel
# (the WLC reassembles). Confirmed: AP joins with this in place. See memory
# cisco-wlc-discovery.
systemd.services.capwap-df-clear = {
description = "Clear DF on lab AP CAPWAP->WLC (10.0.10.10) so DTLS fits the 1420 wg tunnel";
after = [ "network.target" "systemd-networkd.service" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStart = pkgs.writeShellScript "capwap-df-clear-up" ''
set -e
for i in $(seq 1 30); do ${pkgs.iproute2}/bin/ip link show bond.lan254 >/dev/null 2>&1 && break; sleep 1; done
${pkgs.iproute2}/bin/tc qdisc del dev bond.lan254 handle ffff: ingress 2>/dev/null || true
${pkgs.iproute2}/bin/tc qdisc add dev bond.lan254 handle ffff: ingress
${pkgs.iproute2}/bin/tc filter add dev bond.lan254 parent ffff: protocol ip prio 1 u32 \
match ip protocol 17 0xff match ip dst 10.0.10.10/32 \
action pedit ex munge ip df set 0 pipe action csum ip
'';
ExecStop = "-${pkgs.iproute2}/bin/tc qdisc del dev bond.lan254 handle ffff: ingress";
};
};
system.stateVersion = "25.11";
}