Newer
Older
skyworks-Nix-infra / hosts / xlab-gateway / default.nix
# 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";
}