Open Jorman opened 3 years ago
Using the first hop of a traceroute to get vpn_ip
was just a hacky workaround that seemed to work for both Wireguard and OpenVPN, though depending on the setup in some cases might get the wrong ip and fail. Unfortunately we can't use the vpn server ip as we get that 'Unauthorized client' error that you're seeing. I might rename it to api_ip
to make it a bit more clearer.
...continued (I fat fingered and pressed submit)
The ip address to send pf api requests to is the equivalent of the gateway address in OpenVPN, which from what I've seen so far is always 10.x.x.1 with pia. Using traceroute
to guess assumes that all traffic is being sent via Wireguard and it'll simply be the first hop. If it's failing to guess the right ip to send requests to, then for Wireguard you might be able to guess the ip to use based on the 'Address' field in wg0.conf
(eg. if Address = 10.22.33.44/32
, then use -i 10.22.33.1
when running the port forward script).
I'll modify the wg.gen.sh
script to show the correct ip to use as a backup option.
Openwrt has a package called coreutils-base64
that you can use. I use Openwrt myself, though aren't using these scripts on it, so might have a play later to see if there's any other 'gotchas' when using it.
jq has base64 included...
jq -nr "${pf_getsig}"'.payload | @base64d'
Hi, thanks for your reply
Ok, I know that for openvpn protocol, the api_ip
or port-forward service is under a fixed ip, see this portion of code:
PFS_IP="209.222.18.222" # PIA port forwarding service ip
PFS_PORT="2000" # PIA port forwarding service port
But wireguard is different, the port is 19999
and, if I understood that, the ip is different for any server, but is always some like x.x.128.1. I just made a test with some servers:
#cn: milano402
#pf api ip: 10.55.128.1
[Interface]
PrivateKey = ***
Address = 10.55.251.195
DNS = 10.0.0.242,10.0.0.244
-------------------------------
#cn: milano403
#pf api ip: 10.9.128.1
[Interface]
PrivateKey = ***
Address = 10.9.155.222
DNS = 10.0.0.242,10.0.0.244
-------------------------------
#cn: zurich402
#pf api ip: 10.51.128.1
[Interface]
PrivateKey = ***
Address = 10.51.226.118/32
DNS = 10.0.0.242,10.0.0.244
-------------------------------
#cn: morocco402
#pf api ip: 10.17.128.1
[Interface]
PrivateKey = ***
Address = 10.17.192.85/32
DNS = 10.0.0.242,10.0.0.244
So if the server address is 10.33.134.26 the api_ip will be 10.33.128.1, so this can be helpful?
In my case, with openwrt, my wg test network is under TEST_WG_PIA
, so I can use this to guess the api_ip
echo "$(uci get network.TEST_WG_PIA.addresses | grep -o '10\.[0-9]\{1,3\}' ).128.1"
I don't know if you ever used a script to user port-forward on openwrt with openvpn, if you need I can share the Eibgrad script, adapted to openwrt, because was wrote for ddwrt.
Btw I tried again with your indications so:
#cn: milano402
#pf api ip: 10.55.128.1
[Interface]
PrivateKey = ***
Address = 10.55.251.195
DNS = 10.0.0.242,10.0.0.244
[Peer] PublicKey = *** AllowedIPs = 0.0.0.0/0, ::/0 Endpoint = 156.146.41.56:1337
2. I configured the wg interface on the router (remember that the system is configured to route all the wg traffic to one fixed ip on the lan, like the old openvpn)
3. From the router, (that is under normal ip, not wg lan) and this's the result
root@OpenWrt:~# ./pf.sh -t ~/.pia-token -i 10.55.128.1 Sat Sep 19 15:26:16 CEST 2020: API requests may be insecure. Specify a common name using -n. Sat Sep 19 15:26:16 CEST 2020: Getting PF token curl: (28) Connection timed out after 15001 milliseconds Sat Sep 19 15:29:01 CEST 2020: getSignature error
So I modified the script, I added `wg_interface='TEST_WG_PIA'` then all the curl request was made from the wg interface with `curl --interface ${wg_interface} --get ...` and `api_ip` is now `api_ip=$(echo "$(uci get network.${wg_interface}.addresses | grep -o '10\.[0-9]\{1,3\}' ).128.1")`
So I launch the script and this's the result
root@OpenWrt:~# ./pf.sh -t ~/.pia-token Sat Sep 19 21:35:04 CEST 2020: Using 10.55.128.1 as API endpoint Sat Sep 19 21:35:04 CEST 2020: API requests may be insecure. Specify a common name using -n. Sat Sep 19 21:35:04 CEST 2020: Getting PF token Sat Sep 19 21:35:04 CEST 2020: Obtained PF token. Expires at 2020-11-21T07:35:03.021880317Z Sat Sep 19 21:35:04 CEST 2020: Server accepted PF bind Sat Sep 19 21:35:04 CEST 2020: Forwarding on port 23251 Sat Sep 19 21:35:04 CEST 2020: Rebind interval: 900 seconds
But I'm not sure that the port is open
![screen](https://user-images.githubusercontent.com/5203988/93687822-208d8880-fac1-11ea-9c19-0a093aced27b.PNG)
Maybe I've to make the request within 2 min, like the openvpn?
What about Rebind interval? I waited 15mins but no rebind happen, maybe I've to change some?
Do you think is possible to run the script after wg connection like ifup ifdown? Maybe I can try and edit the original Eiggrad script in order to get the port but with the previous script for opevpn I'll check the syslog to check when the connection was established, now there's no info inside syslog
J
Does traceroute -4 -m 1 -i TEST_WG_PIA privateinternetaccess.com
also manage to pick the right api_ip
?
I've had a brief play with the pf script on OpenWrt and after adding an option -f
to specify the interface to use it appears to be working. As long as you get the 'Server accepted PF bind' message, then the vpn server should be forwarding as expected.
However I'm not sure what needs to be done firewall/route wise in order to make use of it with OpenWrt. I briefly tried getting a simple service to accept connections on the forwarded port without luck.
I don't think changing the 'rebind' interval will help. When the script 'rebinds' there won't be any console output unless curl throws an error. You can always replace --silent
with --verbose
if you want to confirm its happening. I imagine the problem is more to do with things being dropped/rejected somewhere rather than the pia api not setting up the forward correctly.
jq has base64 included
That could be useful, cheers.
Yep:
root@OpenWrt:~# traceroute -4 -m 1 privateinternetaccess.com
traceroute to privateinternetaccess.com (95.101.220.236), 1 hops max, 38 byte packets
1 192.168.1.1 (192.168.1.1) 0.693 ms 0.593 ms 0.580 ms
root@OpenWrt:~# traceroute -4 -m 1 -i TEST_WG_PIA privateinternetaccess.com
traceroute to privateinternetaccess.com (95.101.220.236), 1 hops max, 38 byte packets
1 10.55.128.1 (10.55.128.1) 8.481 ms 8.444 ms 8.171 ms
So now for me became api_ip=$(traceroute -4 -m 1 -i $wg_interface privateinternetaccess.com | tail -n 1 | awk '{print $2}')
Or better I can use your -f option ...
The remaining "problem" to my side is:
Modify your script (tell me if I can) in order to launch a callback script if present, after the connection, I think I've to mix your script with EIBGRAD one, for example I can put on your script all the route section that is already present on EIBGRAD script
if [[ "$PROTO" == "both" || "$PROTO" == "udp" ]]; then
# add internal udp port forward
_ipt "-t nat -I PREROUTING -i $dev -p udp -s $SOURCE --dport $pia_ext_port \
-j DNAT --to $INTERNAL_IP:$int_port"
_ipt "-I FORWARD -i $dev -p udp -s $SOURCE -d $INTERNAL_IP \
--dport $int_port -j ACCEPT"
fi
if [[ "$PROTO" == "both" || "$PROTO" == "tcp" ]]; then
# add internal tcp port forward
_ipt "-t nat -I PREROUTING -i $dev -p tcp -s $SOURCE --dport $pia_ext_port \
-j DNAT --to $INTERNAL_IP:$int_port"
_ipt "-I FORWARD -i $dev -p tcp -s $SOURCE -d $INTERNAL_IP \
--dport $int_port -j ACCEPT"
fi
What do you think?
I forgot, for Rebind I mean this:
root@OpenWrt:~# ./pf.sh -t ~/.pia-token
Sun Sep 20 12:20:59 CEST 2020: Using 10.55.128.1 as API endpoint
Sun Sep 20 12:20:59 CEST 2020: API requests may be insecure. Specify a common name using -n.
Sun Sep 20 12:20:59 CEST 2020: Getting PF token
Sun Sep 20 12:20:59 CEST 2020: Obtained PF token. Expires at 2020-11-21T22:20:58.032840755Z
Sun Sep 20 12:20:59 CEST 2020: Server accepted PF bind
Sun Sep 20 12:20:59 CEST 2020: Forwarding on port 23005
Sun Sep 20 12:20:59 CEST 2020: Rebind interval: 900 seconds
What happens after 900 seconds?
What happens after 900 seconds?
Port forwarding on pia used to involve a single (much simpler!) api call to setup. It would only need doing once and would ideally last until the connection went down.
The new api used by their 'next-gen' servers now involves two api calls, one of which (bindPort) appears to need calling every 15mins (900 seconds) in order to keep the port alive. 'Rebinding' just means regularly re-running the bindPort request. It's why the script has to stay running now, whereas previously we just needed to do things just the once.
I've added an option -s
to run another script once the port is ready which might be useful. The forwarded port will be passed as the first argument.
I'm not sure what the best way to overcome the remaining problems would be, as I've not done anything similar with OpenWrt in the past. I might have a further poke around though just for curiosity and will let you know if I have any bright ideas.
Feel free to modify the script as much as you like.
The new api used by their 'next-gen' servers now involves two api calls, one of which (bindPort) appears to need calling every 15mins (900 seconds) in order to keep the port alive. 'Rebinding' just means regularly re-running the bindPort request. It's why the script has to stay running now, whereas previously we just needed to do things just the once.
Ok, so is not ok if after 900 seconds, the script not 'Rebind', am I right? Maybe I only have to adapt your script, but I tried to leave it run for more than 900 seconds and never Rebind, like the loop was not ok, tonight I'll try to put a set -x
to see what happen inside the loop
I've added an option -s to run another script once the port is ready which might be useful. The forwarded port will be passed as the first argument.
Thanks, very appreciated!
I'm not sure what the best way to overcome the remaining problems would be, as I've not done anything similar with OpenWrt in the past. I might have a further poke around though just for curiosity and will let you know if I have any bright ideas.
I've one idea, https://openwrt.org/docs/guide-user/base-system/hotplug can be helpful in this case, I've to make a script and put inside /etc/hotplug.d/iface
so I can specify action when iface is up or down, I've to think about it.
Btw I think that actually port-forward with pia and wg is not working or some, because I tried with the desktop app, and the port is always closed ... And another strange behavior is that if I run the script, then I stop it and re-run again, I get a different port. Is not so good if every 15 minutes I've to change the port inside the client :)
Do you have made some test about it?
J
Ok, I tried with a set -x
and after the sleep the loop restart regularly with bind_port
, so all ok
I've one question, what happen if/when the token will expire? I need to run pia-auth.sh
again?
If yes I think I'll make a new function inside the pf.sh
with the token generation. Any suggestion?
I ask because I don't know wg to much.
I added the firewall rules inside your script, the same that I use in the previous script, for now seems that port-forwarding don't work, neither with Windows app, I'll contact pia for this. Btw this's the rules, I'm still on the old version of your script: new function
_ipt() {
local del_rule="$(echo ${@/-[IA]/-D})"
# precede insert/append w/ deletion to avoid dupes
while iptables $del_rule 2> /dev/null; do :; done
# add firewall rule
iptables $@
# save deletion for future rollback
echo $del_rule >> $ACTIVE_RULES
}
Section with rules
...
bind_port
echo "$(date): Server accepted PF bind"
echo "$(date): Forwarding on port $pf_port"
echo "$(date): Rebind interval: $pf_bindinterval seconds"
# if requested, assign external port to internal port
echo $INTERNAL_PORT | grep -Eq '^-*$' && \
int_port="$pf_port" || int_port="$INTERNAL_PORT"
# add internal udp port forward
_ipt "-t nat -I PREROUTING -i $wg_interface -p udp -s $SOURCE --dport $pf_port \
-j DNAT --to $INTERNAL_IP:$int_port"
_ipt "-I FORWARD -i $wg_interface -p udp -s $SOURCE -d $INTERNAL_IP \
--dport $int_port -j ACCEPT"
# add internal tcp port forward
_ipt "-t nat -I PREROUTING -i $wg_interface -p tcp -s $SOURCE --dport $pf_port \
-j DNAT --to $INTERNAL_IP:$int_port"
_ipt "-I FORWARD -i $wg_interface -p tcp -s $SOURCE -d $INTERNAL_IP \
--dport $int_port -j ACCEPT"
# Dump port here if requested
[ -n "$portfile" ] && echo "$(date): Port dumped to $portfile" && echo $pf_port > "$portfile"
fi
sleep $pf_bindinterval &
wait $!
bind_port
done
my new variables
wg_interface='TEST_WG_PIA'
ACTIVE_RULES="/tmp/$(basename $0 .sh).rules"
SOURCE="0.0.0.0/0"
INTERNAL_IP="$(uci get network.lan.ipaddr)"
INTERNAL_PORT="-"
Like I said I'm still working with your previous version, so I've to specify the interface and I use the nvram for basic information, I'll put the token too inside the nvram.
What do you think?
I'm not sure how long an auth token might last. I've been using it since June and I'm yet to see one expire by itself.
I'm also not sure how long a Wireguard config lasts for. In my case I regenerate it every time the container starts, so haven't had a chance to see it 'naturally' stop working.
Apart from OpenWrt, I haven't had any problems accessing a forwarded port. I've had it working in Windows with and without the app, and from inside a container.
PIA have released their own scripts now, so hopefully someone will soon adapt them to work with OpenWrt.
Good to know! Thanks! Yep, you right, you launch the container. For me the question is slightly different, connection is opened when the router start or if the connection drop for any reason. I'll try to follow the repo you linked to me, for now is not yet fully compatible with openwrt but is a start!
Thank you a lot, your script for now remain very good for me to generate some files and others
J
Hi, this's not an issue, only some information request :)
I've one R7800 with openwrt on it, and with openwrt I modified a script (https://pastebin.com/P9nmpyxh), to run with openwrt. The script get the port forward with "client_id" that is generated with
client_id="$(__hash128)$(__hash128)"
. I'm new with WG, I succesfully configured WG inside the router and routed only to my nas, but I can't find a way to take the port-forwar, I'm at the very beginning. So, I generated the token withpia-auth.sh
and till here all ok, but when I trypf.sh
I get this errorI think I've to adapt the script in some way, first
vpn_ip=$(traceroute -4 -m 1 privateinternetaccess.com | tail -n 1 | awk '{print $2}')
in my case point to my modem. What about some like this?vpn_ip=$(curl --silent --interface $inferface ipinfo.io/ip)
where interface is the interface that run the wg. I know that with this I use an external site, is only one starting point, maybe I can get the wg ip within the router settings too. I said this because I seehttps://$vpn_ip:19999
and I know that there's nothing on 19999 modem port. Second question is, do you think there's an alternative tobase64 -d
? I know that I don't have this on my router so, I'm tying to useopenssl enc -base64 -d
instead but I always got errorI tried even within 2 minutes after wg connection, but with no luck
Any idea?