# SPDX-FileCopyrightText: 2024 Lubin Bailly # # SPDX-License-Identifier: EUPL-1.2 { pkgs, lib, meta, name, config, ... }: let inherit (lib) mapAttrs' mkOption nameValuePair; inherit (lib.types) listOf attrs; uplink = { ip = "10.120.33.250"; prefix = 30; router = "10.120.33.249"; }; mkNetwork = name: { address ? [ ], extraNetwork ? { }, ... }: nameValuePair "10-${name}" ({ inherit name address; } // extraNetwork); mkNetdev = name: { Id, ... }: nameValuePair "10-${name}" { netdevConfig = { Name = name; Kind = "vlan"; }; vlanConfig.Id = Id; }; mkUserVlan = { vlan, netIP, servIP, interfaceName, ... }: { name = interfaceName; value = { Id = vlan; extraNetwork = { networkConfig = { LinkLocalAddressing = "no"; DHCPServer = "yes"; }; linkConfig = { Promiscuous = true; MTUBytes = 1500; }; addresses = [ { Address = "${servIP}/27"; AddPrefixRoute = false; } ]; routes = [ { Destination = "${netIP}/27"; Table = "user"; } ]; }; }; }; userVlans = builtins.genList (id: rec { vlan = 4094 - id; prefix24nb = (id + 1) / 8; prefix27nb = (id + 1 - prefix24nb * 8) * 32; netIP = "10.0.${toString prefix24nb}.${toString prefix27nb}"; servIP = "10.0.${toString prefix24nb}.${toString (prefix27nb + 1)}"; interfaceName = "vlan-user-${toString vlan}"; prefixLen = 27; }) 850; vlans = { vlan-uplink-cri = { Id = 223; address = with uplink; [ "${ip}/${builtins.toString prefix}" ]; extraNetwork = { routes = [ { # Get the public ip from the metadata PreferredSource = builtins.head meta.network.${name}.addresses.ipv4; Gateway = uplink.router; } ]; linkConfig.MTUBytes = 1500; }; }; vlan-admin = { Id = 3000; address = [ "fd26:baf9:d250:8000::1/64" ]; }; vlan-admin-ap = { Id = 3001; address = [ "fd26:baf9:d250:8001::1/64" # FIXME: ipv4 is temporary for APs in production "10.0.253.1/24" ]; extraNetwork = { networkConfig = { IPv6SendRA = true; DHCPServer = "yes"; }; ipv6Prefixes = [ { AddressAutoconfiguration = false; OnLink = false; Prefix = "fd26:baf9:d250:8001::/64"; } ]; }; }; vlan-apro = { Id = 2000; address = [ "10.0.255.1/24" ]; extraNetwork = { networkConfig.DHCPServer = "yes"; linkConfig.MTUBytes = 1500; }; }; vlan-hypervisor = { Id = 2001; address = [ "10.0.254.1/24" ]; extraNetwork = { networkConfig.DHCPServer = "yes"; linkConfig.MTUBytes = 1500; }; }; } // builtins.listToAttrs (map mkUserVlan userVlans); in { options.networking.vlans-info = mkOption { type = listOf attrs; description = '' Information about vlans for log analysis. ''; readOnly = true; }; config = { systemd = { network = { config.routeTables."user" = 1000; networks = { "10-lo" = { name = "lo"; address = [ "::1/128" "127.0.0.1/8" "10.0.0.1/27" ]; routes = [ { Destination = "10.0.0.0/27"; Table = "user"; } ]; routingPolicyRules = [ { To = "10.0.0.0/16"; Table = "user"; } ]; }; "10-enp67s0f0np0" = { name = "enp67s0f0np0"; linkConfig.Promiscuous = true; networkConfig = { Bridge = "br0"; LinkLocalAddressing = false; LLDP = false; EmitLLDP = false; IPv6AcceptRA = false; IPv6SendRA = false; }; linkConfig.MTUBytes = 1504; }; "50-gretap1" = { name = "gretap1"; networkConfig = { Bridge = "br0"; LinkLocalAddressing = false; LLDP = false; EmitLLDP = false; IPv6AcceptRA = false; IPv6SendRA = false; }; linkConfig.MTUBytes = 1504; }; "50-br0" = { name = "br0"; networkConfig = { VLAN = builtins.attrNames vlans; LinkLocalAddressing = false; LLDP = false; EmitLLDP = false; IPv6AcceptRA = false; IPv6SendRA = false; }; linkConfig.MTUBytes = 1504; }; "50-wg0" = { name = "wg0"; address = [ "10.10.17.1/30" ]; networkConfig.Tunnel = "gretap1"; }; } // (mapAttrs' mkNetwork vlans); netdevs = { "50-gretap1" = { netdevConfig = { Name = "gretap1"; Kind = "gretap"; }; tunnelConfig = { Local = "10.10.17.1"; Remote = "10.10.17.2"; }; }; "50-br0" = { netdevConfig = { Name = "br0"; Kind = "bridge"; }; bridgeConfig = { VLANFiltering = false; STP = false; }; }; "50-wg0" = { netdevConfig = { Name = "wg0"; Kind = "wireguard"; }; wireguardConfig = { ListenPort = 1194; PrivateKeyFile = config.age.secrets."wg-key".path; }; wireguardPeers = [ { AllowedIPs = [ "10.10.17.0/30" ]; PublicKey = "g6S3gBx1Hf2iX41tokD+m8WfzJJTTcsKifOkn+Wcd00="; } ]; }; } // mapAttrs' mkNetdev vlans; }; services = { ethtoolConfig = { wantedBy = [ "systemd-networkd.service" ]; after = [ "sys-subsystem-net-devices-enp67s0f0np0.device" ]; bindsTo = [ "sys-subsystem-net-devices-enp67s0f0np0.device" ]; script = builtins.concatStringsSep "\n" ( builtins.map (name: "${lib.getExe pkgs.ethtool} -K enp67s0f0np0 ${name} off") [ "rxvlan" "txvlan" "rx-vlan-filter" "rx-vlan-offload" "tx-vlan-offload" "tx-vlan-stag-hw-insert" ] ); }; systemd-networkd.serviceConfig.LimitNOFILE = 4096; net-checker = { path = [ pkgs.iputils pkgs.systemd ]; script = '' if ping -c 1 8.8.8.8 > /dev/null || ping -c 1 1.1.1.1 > /dev/null; then ${lib.concatMapStringsSep "\n " ( { interfaceName, ... }: "networkctl up ${interfaceName}" ) userVlans} else ${lib.concatMapStringsSep "\n " ( { interfaceName, ... }: "networkctl down ${interfaceName}" ) userVlans} fi ''; }; }; timers.net-checker = { wantedBy = [ "timers.target" ]; timerConfig.OnCalendar = "*-*-* *:*:42"; }; }; networking = { vlans-info = [ { vlan = 2001; netIP = "10.0.254.0"; prefixLen = 24; } { vlan = 3001; netIP = "10.0.253.0"; prefixLen = 24; } ] ++ userVlans; nftables = { enable = true; tables = { nat = { family = "ip"; content = '' chain postrouting { type nat hook postrouting priority 100; ip saddr 10.0.0.0/16 ip daddr != 10.0.0.0/16 snat ip to 129.199.195.130-129.199.195.157 } ''; }; filter = { family = "inet"; content = '' chain forward { type filter hook forward priority filter; policy accept; ct state vmap { invalid: drop, established: accept, related: accept, new: jump forward_decide, untracked: jump forward_decide, }; } chain forward_decide { # Block access to vpn ip daddr { 10.10.17.0/30, 100.80.0.0/16, } jump forward_reject; # And administrative vlans ip6 daddr { fd26:baf9:d250::/48, } jump forward_reject; # These are being deployed, and so are not trusted ip saddr 10.0.255.0/24 jump forward_reject; # We only forward for ISP clients and our stuff ip saddr != 10.0.0.0/16 jump forward_reject; # Can talk to us ip daddr 10.0.0.0/27 accept; # Not others nor CRI ip daddr 10.0.0.0/8 jump forward_reject; } chain forward_reject { reject with icmpx type admin-prohibited; } ''; }; }; }; firewall = { allowedUDPPorts = [ 67 1194 ]; # FIXME: I dont't remember why it's here, and it doesn't seems right # comes from https://git.dgnum.eu/DGNum/infrastructure/commit/411795c664374549e5e831722a80180b51fbf0d5 # checkReversePath = false; }; }; age.secrets."wg-key".owner = "systemd-network"; users.users."systemd-network".extraGroups = [ "keys" ]; boot.kernel.sysctl."net.ipv4.ip_forward" = true; }; }