The relevant part of my config is this:
services.transmission = {
enable = true;
openRPCPort = true;
settings = {
download-dir = "/media/Torrents/Complete";
incomplete-dir = "/media/Torrents/Incomplete";
port-forwarding-enabled = false;
rpc-bind-address = "0.0.0.0";
rpc-whitelist = "127.0.0.*,192.168.*.*";
};
};
systemd.timers."transmission-port-forwarding" = {
wantedBy = ["timers.target"];
timerConfig = {
OnBootSec = "45s";
OnUnitActiveSec = "45s";
Unit = "transmission-port-forwarding.service";
};
};
systemd.services."transmission-port-forwarding" = {
serviceConfig = {
Type = "oneshot";
User = "root";
};
script = ''
set -eu
tcp_port_file="$HOME/.local/state/transmission-tcp-port"
udp_port_file="$HOME/.local/state/transmission-udp-port"
tcp_result="$(${pkgs.libnatpmp}/bin/natpmpc -a 1 0 tcp 60 -g 10.2.0.1)"
udp_result="$(${pkgs.libnatpmp}/bin/natpmpc -a 1 0 udp 60 -g 10.2.0.1)"
echo "$tcp_result"
echo "$udp_result"
new_tcp_port="$(echo "$tcp_result" | ${pkgs.ripgrep}/bin/rg --only-matching --replace '$1' 'Mapped public port (\d+) protocol TCP to local port 0 lifetime 60')"
old_tcp_port="$(cat "$tcp_port_file")"
echo "New TCP port $new_tcp_port replacing old TCP port $old_tcp_port."
echo "$new_tcp_port" >"$tcp_port_file"
new_udp_port="$(echo "$udp_result" | ${pkgs.ripgrep}/bin/rg --only-matching --replace '$1' 'Mapped public port (\d+) protocol UDP to local port 0 lifetime 60')"
old_udp_port="$(cat "$udp_port_file")"
echo "New UDP port $new_udp_port replacing old UDP port $old_udp_port."
echo "$new_udp_port" >"$udp_port_file"
if [ "$new_tcp_port" -ne "$new_udp_port" ]
then
echo "New TCP port $new_tcp_port does not match new UDP port $new_udp_port, doing nothing as things will almost certainly break."
exit 3
elif [ "$old_tcp_port" -ne "$new_tcp_port" -o "$old_udp_port" -ne "$new_udp_port" ]
then
echo "Opening new TCP port $new_tcp_port."
${pkgs.iptables}/bin/iptables -A INPUT -p tcp --dport "$new_tcp_port" -j ACCEPT
echo "Opening new UDP port $new-udp-port."
${pkgs.iptables}/bin/iptables -A INPUT -p udp --dport "$new_udp_port" -j ACCEPT
echo "Updating transmission peer-port to $new_tcp_port."
${pkgs.transmission}/bin/transmission-remote --port "$new_tcp_port"
if [ "$old_tcp_port" -ne "$new_tcp_port" -a "$old_tcp_port" -ne '-1' ]
then
echo "Closing old TCP port $old_tcp_port."
${pkgs.iptables}/bin/iptables -D INPUT -p tcp --dport "$old_tcp_port" -j ACCEPT
else
echo "Old TCP port is $old_tcp_port, not closing."
fi
if [ "$old_udp_port" -ne "$new_udp_port" -a "$old_udp_port" -ne '-1' ]
then
echo "Closing old UDP port $old_udp_port."
${pkgs.iptables}/bin/iptables -D INPUT -p udp --dport "$old_udp_port" -j ACCEPT
else
echo "Old UDP port is $old_udp_port, not closing."
fi
else
echo 'Old and new ports are identical, doing nothing.'
fi
'';
};
(apologies for how bad that script is, I was just trying to get it to work first…)
I set up ProtonVPN using nmcli (since I couldn’t get the CLI client to work and I’m running this on a headless RPi), using the UK#77 server (which has P2P enabled) and appending +pmp
to the OpenVPN username (as specified here):
$ nmcli connection show | rg uk-77
uk-77.protonvpn.udp b70e0f1e-b089-459f-b89e-95ad43424e1e vpn wlan0
$ nmcli connection show uk-77.protonvpn.udp | rg user-name
vpn.user-name: ????????????????+pmp
From the perspective of my machine, everything seems to be working fine. I can connect to the transmission web UI from my laptop and it has the right port number, the IP of the RPi matches one of Proton’s IPs and not my home IP, the port-forwarding script seems to work fine
$ journalctl -u transmission-port-forwarding
Jan 18 20:19:17 vpn systemd[1]: Starting transmission-port-forwarding.service...
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: initnatpmp() returned 0 (SUCCESS)
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: using gateway : 10.2.0.1
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: sendpublicaddressrequest returned 2 (SUCCESS)
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: readnatpmpresponseorretry returned 0 (OK)
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: Public IP address : 146.70.133.136
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: epoch = 4434776
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: sendnewportmappingrequest returned 12 (SUCCESS)
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: readnatpmpresponseorretry returned 0 (OK)
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: Mapped public port 50131 protocol TCP to local port 0 lifetime 60
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: epoch = 4434776
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: closenatpmp() returned 0 (SUCCESS)
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: initnatpmp() returned 0 (SUCCESS)
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: using gateway : 10.2.0.1
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: sendpublicaddressrequest returned 2 (SUCCESS)
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: readnatpmpresponseorretry returned 0 (OK)
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: Public IP address : 146.70.133.136
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: epoch = 4434776
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: sendnewportmappingrequest returned 12 (SUCCESS)
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: readnatpmpresponseorretry returned 0 (OK)
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: Mapped public port 50131 protocol UDP to local port 0 lifetime 60
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: epoch = 4434776
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: closenatpmp() returned 0 (SUCCESS)
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: New TCP port 50131 replacing old TCP port 50131.
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: New UDP port 50131 replacing old UDP port 50131.
Jan 18 20:19:18 vpn transmission-port-forwarding-start[39651]: Old and new ports are identical, doing nothing.
Jan 18 20:19:18 vpn systemd[1]: transmission-port-forwarding.service: Deactivated successfully.
Jan 18 20:19:18 vpn systemd[1]: Finished transmission-port-forwarding.service.
Jan 18 20:19:18 vpn systemd[1]: transmission-port-forwarding.service: Consumed 45ms CPU time, received 168B IP traffic, sent 140B IP traffic.
and the port is open in my iptables
output:
$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
nixos-fw all -- anywhere anywhere
ACCEPT udp -- anywhere anywhere udp dpt:50131
ACCEPT tcp -- anywhere anywhere tcp dpt:50131
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain nixos-drop (0 references)
target prot opt source destination
DROP all -- anywhere anywhere
Chain nixos-fw (1 references)
target prot opt source destination
nixos-fw-accept all -- anywhere anywhere
nixos-fw-accept all -- anywhere anywhere ctstate RELATED,ESTABLISHED
nixos-fw-accept tcp -- anywhere anywhere tcp dpt:ssh
nixos-fw-accept tcp -- anywhere anywhere tcp dpt:xmltec-xmlmail
nixos-fw-accept icmp -- anywhere anywhere icmp echo-request
nixos-fw-log-refuse all -- anywhere anywhere
Chain nixos-fw-accept (5 references)
target prot opt source destination
ACCEPT all -- anywhere anywhere
Chain nixos-fw-log-refuse (1 references)
target prot opt source destination
LOG tcp -- anywhere anywhere tcp flags:FIN,SYN,RST,ACK/SYN LOG level info prefix "refused connection: "
nixos-fw-refuse all -- anywhere anywhere PKTTYPE != unicast
nixos-fw-refuse all -- anywhere anywhere
Chain nixos-fw-refuse (2 references)
target prot opt source destination
DROP all -- anywhere anywhere
However the Transmission Web UI says that the port is closed, and https://canyouseeme.org reports that the port is closed as well (although I’m checking that using an SSH tunnel, so maybe that’s causing issues?).
Any ideas what is causing this? My current thinking is that I’m not handling iptables
correctly, but I have no idea in what way…