1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
---
title: "I paid for the whole vpn, so I'm damn well going to use the whole vpn"
tags: ["sysadmin"]
categories: ["Life of a sysadmin"]
draft: true
---
_Or: hand roll a ngrok with protonvpn port forwarding, for shits and giggles_
# Dumbness: port forward `sshd`
Our general plan is this:
Bring up a wireguard tunnel to protonvpn as usual.
Bring up sshd as usual.
Port forward some public port to `10.2.0.2:22`, with `natpmpc(1)`.
The first two steps are just the standard issue procedure, I won't go over it here. I'll assume the wireguard config is placed at `/etc/wireguard/protonvpn.conf`, so bringing it up is simply `wg-quick up protonvpn`.
Also remember to harden `sshd`, like disable password login and setup fail2ban. Otherwise you'll have a pretty bad day...
First, the port forwarding logic.
It's a simple bash script `/usr/local/bin/protonvpn-update-port-mapping`, adapted from [here](https://github.com/giu176/ProtonVPN-auto-NATPMP/blob/main/natpmpc_script.sh).
```bash
#!/bin/bash
TMPFILE=/tmp/natpmpc_output
# We can assume the exit node IP doesn't change
ip=$(curl -s --interface=protonvpn -4 icanhazip.com)
echo "$ip" > "$RUNTIME_DIRECTORY/public-ip"
ip6=$(curl -s --interface=protonvpn -6 icanhazip.com)
echo "$ip6" > "$RUNTIME_DIRECTORY/public-ip6"
while true; do
natpmpc -a 1 22 udp 60 -g 10.2.0.1 > /dev/null \
&& natpmpc -a 1 22 tcp 60 -g 10.2.0.1 > $TMPFILE \
|| {
echo -e "ERROR with natpmpc command \a"
break
}
port=$(grep 'TCP' $TMPFILE | grep -o 'Mapped public port [0-9]*' | awk '{print $4}')
rm $TMPFILE
echo "$port" > "$RUNTIME_DIRECTORY/public-port"
sleep 45
done
```
In the script provided in [protonvpn docs](https://protonvpn.com/support/port-forwarding-manual-setup), natpmpc is called with privateport = 0, which means use the same port as the public port, allocated by the gateway.
Changing it to 22 makes it so that the gateway still chooses whatever it wants, but the privateport is always mapped to 22, on which sshd is listening.
You'll notice we map UDP on line 12, in addition to TCP on line 13.
Indeed it's not necessary for sshd, but I'm going to reference this same script in the wireguard section below, which does need UDP.
Second, a systemd service `/etc/systemd/system/protonvpn-natpmp.service`.
Note `[email protected]` is a template provided in the most linux distros just runs wg-quick on the pprovided config.
And setting `RuntimeDirectory` will create the `$RUNTIME_DIRECTORY` env var used by the script above.
```ini
[Unit]
Description=ProtonVPN NAT-PMP port forwarding update
[email protected]
[email protected]
[Service]
Type=exec
ExecStart=/usr/local/bin/protonvpn-update-port-mapping
RuntimeDirectory=protonvpn-natpmp
# Harden, because why not
ProtectSystem=strict
PrivateTmp=true
ProtectHome=true
PrivateDevices=true
ProtectKernelTunables=true
ProtectControlGroups=true
[Install]
WantedBy=multi-user.target
```
Reload to pick up the new unit files.
Enable and immediately start both services:
```
# systemctl daemon-reload
# systemctl enable --now [email protected] protonvpn-natpmp.service
```
Read the public address under `/run/protonvpn`, now you should be able to ssh, from anywhere on the internet, to this machine.
# Sillinessw: port forward wireguard
TODO
|