at 25.11-pre 4.1 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8with lib; 9 10let 11 cfg = config.services.miniupnpd; 12 configFile = pkgs.writeText "miniupnpd.conf" '' 13 ext_ifname=${cfg.externalInterface} 14 enable_natpmp=${if cfg.natpmp then "yes" else "no"} 15 enable_upnp=${if cfg.upnp then "yes" else "no"} 16 17 ${concatMapStrings (range: '' 18 listening_ip=${range} 19 '') cfg.internalIPs} 20 21 ${lib.optionalString (firewall == "nftables") '' 22 upnp_table_name=miniupnpd 23 upnp_nat_table_name=miniupnpd 24 ''} 25 26 ${cfg.appendConfig} 27 ''; 28 firewall = if config.networking.nftables.enable then "nftables" else "iptables"; 29 miniupnpd = pkgs.miniupnpd.override { inherit firewall; }; 30 firewallScripts = lib.optionals (firewall == "iptables") ( 31 [ "iptables" ] ++ lib.optional (config.networking.enableIPv6) "ip6tables" 32 ); 33in 34{ 35 options = { 36 services.miniupnpd = { 37 enable = mkEnableOption "MiniUPnP daemon"; 38 39 externalInterface = mkOption { 40 type = types.str; 41 description = '' 42 Name of the external interface. 43 ''; 44 }; 45 46 internalIPs = mkOption { 47 type = types.listOf types.str; 48 example = [ 49 "192.168.1.1/24" 50 "enp1s0" 51 ]; 52 description = '' 53 The IP address ranges to listen on. 54 ''; 55 }; 56 57 natpmp = mkEnableOption "NAT-PMP support"; 58 59 upnp = mkOption { 60 default = true; 61 type = types.bool; 62 description = '' 63 Whether to enable UPNP support. 64 ''; 65 }; 66 67 appendConfig = mkOption { 68 type = types.lines; 69 default = ""; 70 description = '' 71 Configuration lines appended to the MiniUPnP config. 72 ''; 73 }; 74 }; 75 }; 76 77 config = mkIf cfg.enable { 78 networking.firewall.extraCommands = lib.mkIf (firewallScripts != [ ]) ( 79 builtins.concatStringsSep "\n" ( 80 map (fw: '' 81 EXTIF=${cfg.externalInterface} ${pkgs.bash}/bin/bash -x ${miniupnpd}/etc/miniupnpd/${fw}_init.sh 82 '') firewallScripts 83 ) 84 ); 85 86 networking.firewall.extraStopCommands = lib.mkIf (firewallScripts != [ ]) ( 87 builtins.concatStringsSep "\n" ( 88 map (fw: '' 89 EXTIF=${cfg.externalInterface} ${pkgs.bash}/bin/bash -x ${miniupnpd}/etc/miniupnpd/${fw}_removeall.sh 90 '') firewallScripts 91 ) 92 ); 93 94 networking.nftables = lib.mkIf (firewall == "nftables") { 95 # see nft_init in ${miniupnpd-nftables}/etc/miniupnpd 96 tables.miniupnpd = { 97 family = "inet"; 98 # The following is omitted because it's expected that the firewall is to be responsible for it. 99 # 100 # chain forward { 101 # type filter hook forward priority filter; policy drop; 102 # jump miniupnpd 103 # } 104 # 105 # Otherwise, it quickly gets ugly with (potentially) two forward chains with "policy drop". 106 # This means the chain "miniupnpd" never actually gets triggered and is simply there to satisfy 107 # miniupnpd. If you're doing it yourself (without networking.firewall), the easiest way to get 108 # it to work is adding a rule "ct status dnat accept" - this is what networking.firewall does. 109 # If you don't want to simply accept forwarding for all "ct status dnat" packets, override 110 # upnp_table_name with whatever your table is, create a chain "miniupnpd" in your table and 111 # jump into it from your forward chain. 112 content = '' 113 chain miniupnpd {} 114 chain prerouting_miniupnpd { 115 type nat hook prerouting priority dstnat; policy accept; 116 } 117 chain postrouting_miniupnpd { 118 type nat hook postrouting priority srcnat; policy accept; 119 } 120 ''; 121 }; 122 }; 123 124 systemd.services.miniupnpd = { 125 description = "MiniUPnP daemon"; 126 after = [ "network.target" ]; 127 wantedBy = [ "multi-user.target" ]; 128 serviceConfig = { 129 ExecStart = "${miniupnpd}/bin/miniupnpd -f ${configFile}"; 130 PIDFile = "/run/miniupnpd.pid"; 131 Type = "forking"; 132 }; 133 }; 134 }; 135}