Newer
Older
skyworks-Nix-infra / hosts / xlab-gateway / networking.nix
# xlab-gateway networking
# Bond (balance-xor) → VLANs (lan254, wan99, mgmt) → MACVLAN (wan99.0)
# WireGuard tunnels with policy routing ("freedom" tables)
# NAT/masquerade on wan99.0
{ config, ... }:

{
  networking = {
    useNetworkd = true;
    useDHCP = false;

    nftables = {
      enable = true;
      ruleset = ''
        table ip filter {
          set bogons_v4 {
            type ipv4_addr
            flags interval
            elements = {
              0.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8,
              169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24,
              192.168.0.0/16, 198.18.0.0/15, 198.51.100.0/24, 203.0.113.0/24,
              224.0.0.0/4, 240.0.0.0/4
            }
          }

          chain prerouting {
            type filter hook prerouting priority raw; policy accept;
            iifname "wan99.0" ip saddr @bogons_v4 drop
          }

          chain forward {
            type filter hook forward priority filter; policy drop;
            iifname { "bond.lan254", "wg-to-wgnet" } accept
            iifname "wan99.0" ct state established,related accept
          }
        }

        table ip6 filter {
          chain forward {
            type filter hook forward priority filter; policy drop;
            iifname { "bond.lan254", "wg-to-wgnet" } accept
            iifname "wan99.0" ct state established,related accept
          }
        }

        table inet nat {
          chain postrouting {
            type nat hook postrouting priority filter; policy accept;
            oifname "wan99.0" masquerade
          }
        }

        table inet mangle {
          chain postrouting {
            type filter hook postrouting priority filter; policy accept;
            oifname "wg-*" tcp flags syn tcp option maxseg size set 1380
          }
        }
      '';
    };

    firewall.enable = false;  # Using nftables directly
  };

  # Custom routing table names
  environment.etc."iproute2/rt_tables.d/skyworks.conf".text = ''
    1000 freedom
    1001 freedom-extra
    1002 wg-to-skywme
    1003 wg-to-skyworks
  '';

  # ===========================================================================
  # NETDEVS
  # ===========================================================================
  systemd.network.netdevs = {
    "10-bond" = {
      netdevConfig = {
        Name = "bond";
        Kind = "bond";
        Description = "Main aggregated interface";
      };
      bondConfig = {
        Mode = "balance-xor";
      };
    };

    "20-bond-lan254" = {
      netdevConfig = {
        Name = "bond.lan254";
        Kind = "vlan";
      };
      vlanConfig.Id = 10;
    };

    "20-bond-wan99" = {
      netdevConfig = {
        Name = "bond.wan99";
        Kind = "vlan";
      };
      vlanConfig.Id = 99;
    };

    "20-bond-mgmt" = {
      netdevConfig = {
        Name = "bond.mgmt";
        Kind = "vlan";
      };
      vlanConfig.Id = 1;
    };

    "30-wan99-0" = {
      netdevConfig = {
        Name = "wan99.0";
        Kind = "macvlan";
        MACAddress = "90:e2:ba:54:26:90";
      };
      macvlanConfig.Mode = "bridge";
    };

    "40-wg-to-wgnet" = {
      netdevConfig = {
        Name = "wg-to-wgnet";
        Kind = "wireguard";
      };
      wireguardConfig = {
        PrivateKeyFile = config.age.secrets.xlab-wg-wgnet.path;
      };
      wireguardPeers = [
        {
          PublicKey = "H+PAPw+1MsE50Of4VMMPzMbzGG731CkNrIgaXbxcFwk=";
          PresharedKeyFile = config.age.secrets.xlab-wg-wgnet-psk.path;
          AllowedIPs = [ "0.0.0.0/0" "::/0" ];
          Endpoint = "166.111.17.108:51820";
          PersistentKeepalive = 16;
        }
      ];
    };

    "40-wg-to-skyworks" = {
      netdevConfig = {
        Name = "wg-to-skyworks";
        Kind = "wireguard";
      };
      wireguardConfig = {
        PrivateKeyFile = config.age.secrets.xlab-wg-skyworks.path;
      };
      wireguardPeers = [
        {
          PublicKey = "yyHQ8fg1riI9BJPUjydh/C2MTiA/p0Pb1f9Hc88BuCk=";
          AllowedIPs = [ "0.0.0.0/0" "::/0" ];
          Endpoint = "wgep.thu-skyworks.org:16777";
          PersistentKeepalive = 20;
        }
      ];
    };
  };

  # ===========================================================================
  # NETWORKS
  # ===========================================================================
  systemd.network.networks = {
    # Bond slaves
    "10-bond-slaves" = {
      matchConfig.Name = "enp3s0f0 enp3s0f1";
      networkConfig = {
        Bond = "bond";
        IPv6AcceptRA = false;
        LLDP = false;
      };
    };

    # Bond master
    "20-bond" = {
      matchConfig.Name = "bond";
      linkConfig.RequiredForOnline = "no";
      networkConfig = {
        VLAN = [ "bond.mgmt" "bond.wan99" "bond.lan254" ];
        DHCP = "no";
        IPv6AcceptRA = false;
      };
    };

    # LAN - 10.253.254.0/24
    "30-bond-lan254" = {
      matchConfig.Name = "bond.lan254";
      networkConfig = {
        DHCP = "no";
        Address = [
          "10.253.254.1/24"
          "fd99:23eb:1682:fd:df::1/80"
        ];
        IPv6AcceptRA = false;
      };
      routes = [
        { Destination = "10.0.0.0/16"; Gateway = "10.253.0.1"; }
        # Throw routes for Tsinghua ranges → punches holes in WireGuard table
        { Destination = "166.111.0.0/16"; Type = "throw"; Table = 1002; }
        { Destination = "101.5.0.0/16"; Type = "throw"; Table = 1002; }
        { Destination = "101.6.0.0/16"; Type = "throw"; Table = 1002; }
        { Destination = "59.66.0.0/16"; Type = "throw"; Table = 1002; }
        { Destination = "183.172.0.0/16"; Type = "throw"; Table = 1002; }
        { Destination = "183.173.0.0/16"; Type = "throw"; Table = 1002; }
        { Destination = "2402:f000::/32"; Type = "throw"; Table = 1002; }
      ];
      routingPolicyRules = [
        # Use main table only for specific routes (not default)
        {
          SuppressPrefixLength = 0;
          Family = "both";
          Priority = 100;
        }
        # All traffic → WireGuard routing table
        {
          Table = 1002;
          Priority = 20000;
          Family = "both";
        }
      ];
    };

    # Management - 192.168.1.0/24
    "30-bond-mgmt" = {
      matchConfig.Name = "bond.mgmt";
      networkConfig.DHCP = "no";
      addresses = [{ Address = "192.168.1.13/24"; }];
    };

    # WAN VLAN trunk
    "30-bond-wan99" = {
      matchConfig.Name = "bond.wan99";
      linkConfig.RequiredForOnline = "no";
      networkConfig = {
        MACVLAN = [ "wan99.0" ];
        DHCP = "no";
        IPv6AcceptRA = false;
      };
    };

    # WAN uplink (DHCP)
    "40-wan99-0" = {
      matchConfig.Name = "wan99.0";
      networkConfig = {
        NTP = [
          "ntp.tuna.tsinghua.edu.cn"
          "ntp1.aliyun.com"
          "ntp.ntsc.ac.cn"
        ];
        DNS = [ "166.111.8.28" "166.111.8.29" ];
        DHCP = "yes";
      };
      dhcpV4Config = {
        RouteMTUBytes = "1500";
        DUIDType = "link-layer-time";
        UseDNS = false;
      };
      dhcpV6Config = {
        DUIDType = "link-layer-time";
        UseDNS = false;
      };
      ipv6AcceptRAConfig = {
        UseAutonomousPrefix = false;
        UseDNS = false;
      };
    };

    # WireGuard: wg-to-wgnet (main tunnel for "freedom" routing)
    "50-wg-to-wgnet" = {
      matchConfig.Name = "wg-to-wgnet";
      addresses = [
        { Address = "10.253.1.37/32"; }
        { Address = "fd99:23eb:1682:fd::128/128"; }
      ];
      routes = [
        { Destination = "0.0.0.0/0"; Scope = "link"; Table = 1002; }
        { Destination = "::/0"; Scope = "link"; Table = 1002; }
      ];
    };

    # WireGuard: wg-to-skyworks
    "50-wg-to-skyworks" = {
      matchConfig.Name = "wg-to-skyworks";
      addresses = [
        { Address = "10.239.0.9/16"; }
        { Address = "fd5b:8249:afe:cb9a::9/64"; }
      ];
      routes = [
        { Destination = "10.0.2.144/32"; }
        { Destination = "10.74.0.0/16"; }
      ];
    };
  };

  # ===========================================================================
  # AGENIX SECRETS
  # ===========================================================================
  age.secrets = {
    xlab-wg-wgnet = {
      file = ../../secrets/xlab-wg-wgnet.age;
      owner = "systemd-network";
      mode = "0400";
    };
    xlab-wg-wgnet-psk = {
      file = ../../secrets/xlab-wg-wgnet-psk.age;
      owner = "systemd-network";
      mode = "0400";
    };
    xlab-wg-skyworks = {
      file = ../../secrets/xlab-wg-skyworks.age;
      owner = "systemd-network";
      mode = "0400";
    };
  };
}