{ pkgs, lib, config, ... }:
with lib;
let
- inherit (config.users) users;
+ inherit (config.users) users groups;
cfg = config.services.upnpc;
getInfo = ''
while IFS=: read -r k v; do
systemd.services = listToAttrs (map (r:
nameValuePair "upnpc-${toString r.internalPort}" (mkMerge [
{ description = "UPnP ${toString r.internalPort}";
- after = [ "network-online.target" ];
+ after = [ "network-pre.target" ];
#wantedBy = [ "multi-user.target" ];
path = [ pkgs.miniupnpc ];
serviceConfig = {
) cfg.redirections);
# This enables to match on the uid in the firewall.
- users.users."upnpc".isSystemUser = true;
+ users.users."upnpc" = {
+ isSystemUser = true;
+ group = groups."upnpc".name;
+ };
+ users.groups."upnpc" = {};
+ networking.nftables.ruleset =
+ lib.optionalString (cfg.redirections != []) ''
+ table inet filter {
+ # A set containing the udp port(s) to which SSDP replies are allowed.
+ set upnpc-ssdp {
+ type inet_service
+ timeout 5s
+ }
+ chain input-net {
+ # Create a rule for accepting any SSDP packets going to a remembered port.
+ udp dport @upnpc-ssdp counter accept comment "SSDP answer"
+ }
+ chain output-net {
+ skuid ${users.upnpc.name} \
+ tcp dport ssdp \
+ counter accept \
+ comment "SSDP automatic opening"
+ skuid ${users.upnpc.name} \
+ ip daddr 239.255.255.250 udp dport ssdp \
+ set add udp sport @upnpc-ssdp \
+ comment "SSDP automatic opening"
+ skuid ${users.upnpc.name} \
+ ip daddr 239.255.255.250 udp dport ssdp \
+ counter accept \
+ comment "SSDP"
+ }
+ }
+ '' + lib.optionalString config.networking.enableIPv6 ''
+ table inet filter {
+ chain output-net {
+ skuid ${users.upnpc.name} \
+ ip6 daddr { FF02::C, FF05::C, FF08::C, FF0E::C } \
+ udp dport ssdp \
+ set add udp sport @upnpc-ssdp \
+ comment "SSDP automatic opening"
+ skuid ${users.upnpc.name} \
+ ip6 daddr { FF02::C, FF05::C, FF08::C, FF0E::C } \
+ udp dport ssdp \
+ counter accept comment "SSDP"
+ }
+ }
+ '';
};
meta.maintainers = with maintainers; [ julm ];
}