thrnz / docker-wireguard-pia

A Docker container for using Wireguard with PIA.
269 stars 54 forks source link

Information request #4

Open Jorman opened 3 years ago

Jorman commented 3 years ago

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 with pia-auth.sh and till here all ok, but when I try pf.sh I get this error

root@OpenWrt:~# ./pf.sh -t ~/.pia-token
Sat Sep 19 00:11:39 CEST 2020: Automatically getting API IP failed.
Sat Sep 19 00:11:39 CEST 2020: Fatal error

I 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 see https://$vpn_ip:19999 and I know that there's nothing on 19999 modem port. Second question is, do you think there's an alternative to base64 -d? I know that I don't have this on my router so, I'm tying to use openssl enc -base64 -d instead but I always got error

++ curl --get --silent --show-error --retry 5 --retry-delay 15 --max-time 15 --data-urlencode token=token --insecure https://156.146.41.57:19999/getSignature
+ pf_getsig='{
    "status": "ERROR",
    "message": "Unauthorized client"
}'

I tried even within 2 minutes after wg connection, but with no luck

Any idea?

thrnz commented 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.

thrnz commented 3 years ago

...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.

austensmith commented 3 years ago

jq has base64 included...

jq -nr "${pf_getsig}"'.payload | @base64d'

Jorman commented 3 years ago

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:

  1. I run wg-gen.sh, and I get the .conf
    
    #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
thrnz commented 3 years ago

Does traceroute -4 -m 1 -i TEST_WG_PIA privateinternetaccess.com also manage to pick the right api_ip?

thrnz commented 3 years ago

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.

Jorman commented 3 years ago

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:

  1. Understand if I can run a script right after the iface was up (I think I'll have to ask to openwrt forum)
  2. 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
  3. Understand if I can watch the connection status, that is quite the same of 1st question, directly correlated
  4. Understand if the port-forward is actually working (lol, maybe this must be the 1st point!)

What do you think?

Jorman commented 3 years ago

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?

thrnz commented 3 years ago

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.

Jorman commented 3 years ago

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

Jorman commented 3 years ago

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?

thrnz commented 3 years ago

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.

Jorman commented 3 years ago

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