From 35c9f2bf6065363e4a700020b063b9160d929400 Mon Sep 17 00:00:00 2001 From: Colin Date: Sun, 28 May 2023 20:38:24 +0000 Subject: [PATCH] servo: enable UPnP port forwarding timer --- hosts/by-name/servo/net.nix | 1 + modules/services/wan-ports.nix | 60 ++++++++++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/hosts/by-name/servo/net.nix b/hosts/by-name/servo/net.nix index 3b6b3b47..a034107b 100644 --- a/hosts/by-name/servo/net.nix +++ b/hosts/by-name/servo/net.nix @@ -4,6 +4,7 @@ networking.domain = "uninsane.org"; sane.services.wan-ports.openFirewall = true; + sane.services.wan-ports.openUpnp = true; # The global useDHCP flag is deprecated, therefore explicitly set to false here. # Per-interface useDHCP will be mandatory in the future, so this generated config diff --git a/modules/services/wan-ports.nix b/modules/services/wan-ports.nix index 6e4140cc..5edaee61 100644 --- a/modules/services/wan-ports.nix +++ b/modules/services/wan-ports.nix @@ -1,4 +1,4 @@ -{ config, lib, ... }: +{ config, lib, pkgs, ... }: let cfg = config.sane.services.wan-ports; in @@ -9,14 +9,32 @@ in default = false; type = types.bool; }; - - # TODO: openUpnp option + openUpnp = mkOption { + default = false; + type = types.bool; + }; + upnpRenewInterval = mkOption { + default = "1hr"; + type = types.str; + description = "how frequently to renew UPnP leases"; + }; + upnpLeaseDuration = mkOption { + default = 86400; + type = types.int; + description = "how long to lease UPnP ports for"; + }; # TODO: rework this to look like: # ports.53 = { # protocol = [ "udp" "tcp" ]; # have this be default # visibility = "wan"; # or "lan" # } + # or maybe: + # tcp.ports.53 = { + # visibility = "wan"; # or "lan" + # }; + # and a special convertibleTo to handle port ranges + # plus aggregation to convert individual ports back to ranges before doing certain operations (like UPnP?) tcp = mkOption { type = types.listOf types.int; default = []; @@ -28,8 +46,36 @@ in }; }; - config = lib.mkIf cfg.openFirewall { - networking.firewall.allowedTCPPorts = cfg.tcp; - networking.firewall.allowedUDPPorts = cfg.udp; - }; + config = lib.mkMerge [ + (lib.mkIf cfg.openFirewall { + networking.firewall.allowedTCPPorts = cfg.tcp; + networking.firewall.allowedUDPPorts = cfg.udp; + }) + (lib.mkIf cfg.openUpnp { + systemd.services.upnp-forwards = { + description = "forward ports from upstream gateway to this host"; + serviceConfig.Type = "oneshot"; + restartTriggers = [(builtins.toJSON cfg)]; + + after = [ "network.target" ]; + script = + let + forwards = + (builtins.map (p: "tcp:${builtins.toString p}") cfg.tcp) ++ + (builtins.map (p: "udp:${builtins.toString p}") cfg.udp); + in '' + ${pkgs.sane-scripts}/bin/sane-ip-port-forward -v -d ${builtins.toString cfg.upnpLeaseDuration} \ + ${builtins.concatStringsSep " " forwards} + ''; + }; + + systemd.timers.upnp-forwards = { + wantedBy = [ "network.target" ]; + timerConfig = { + OnStartupSec = "1min"; + OnUnitActiveSec = cfg.upnpRenewInterval; + }; + }; + }) + ]; }