Port Forwarding Without The Application (Advanced Users)

edited October 2014 in VPN Setup Support Posts: 162
You want it, we've got it.  (i.e., ask and ye' shall receive)

If you are looking for port forwarding, the best bet is to use our application.

If you are a highly advanced user who wishes to enable port forwarding without using our state of the art application, you can still do so by utilizing our simple, SSL secured API interface:

Vars:     user=username
          pass=password
          client_id=a random string that no one should be able to guess, use the same string every time
          local_ip=the 10.x.x.x IP you get assigned after connecting to the VPN

Make client_id:
osx:   head -n 100 /dev/urandom | md5 > ~/.pia_client_id
linux: head -n 100 /dev/urandom | md5sum > ~/.pia_client_id
EDIT:  linux: head -n 100 /dev/urandom | md5sum | tr -d " -" > ~/.pia_client_id 
(Thanks rcbarnes)

curl -d "user=USERNAME&pass=PASSWORD&client_id=$(cat ~/.pia_client_id)&local_ip=LOCAL_IP" https://www.privateinternetaccess.com/vpninfo/port_forward_assignment

RETURNS:
{ "port": 23423 }

You can easily make a script and call it in the 'up' section of the OpenVPN configuration.  You will need to save the JSON output and act accordingly.  Please remember that port forwarding to the router, for example, means that a port forward from the router to the device behind the router will be required.  This is for highly advanced users.

Please make the call to this API at least once every hour.

Edit: Please make sure that the HTTPS call is routed out over the OpenVPN tunnel, if you're utilizing a setup where not all traffic is routed, you will need to write your code to properly route the call over the tunnel!
Post edited by Support on
«13456715

Comments

  • Brilliant!  Experimenting with it now...


    I will report back once I learn or verify anything.
  • Useful (for me) snippets to add to the discussion (tested on my recent TomatoUSB firmware which has extra software installed through optware so until later when I verify what is included with default ROMs, YMMV greatly); these are pretty trivial, but other scripters might appreciate not having to write/test/validate their own handling of the text processing for full automation:

    # Detect (and save) your tunnel's IP address, needed for building the URL to POST
    ifconfig tun11|grep -oE "inet addr: *10\.[0-9]+\.[0-9]+\.[0-9]+"|tr -d "a-z :"|tee /tmp/vpn_ip

    # Detect (and save) your world-visible IP, assuming the default assignment of vlan2 for VPN tunnel #1
    route -n|grep "vlan2$"|grep -v "0\.0\.0\.0"|cut -d " " -f 1|tee /tmp/vpn_external_ip

    # Extract (and save) the port number returned from the POST curl command which is suggested in the original post (replace [...] with the command, of course)
    [...] 2>/dev/null|grep -oE "[0-9]+"|tee /tmp/vpn_port_opened

  • Also, I used:
    head -n 100 /dev/urandom | md5sum | tr -d " -" > ~/.pia_client_id

    instead of :
    head -n 100 /dev/urandom | md5sum > ~/.pia_client_id

    which creates a client ID string that's easier/safer to use than the one the original command wrote.  Particularly, my string does not contain the unnecessary space and hyphen, which obviates the need to encode the space to make the URL standards-compliant, as well as preventing that space from turning an insufficiently quoted URL into separate strings (with possible havoc from the apparent argument created by starting the second string with '-'!) when read by the shell.
  • edited September 2012 Posts: 10
    hello,

     i am trying my luck here.... but where do find the pia_client_id after running the command?

     Make client_id:
    osx:   head -n 100 /dev/urandom | md5 > ~/.pia_client_id

     i don't get a terminal output.

    nevermind slight syntax mix up without the ">" does the trick.

    now i get an assigned port with the curl command, but unfortunately the port is different to the port when usin the pia client and is not considered "opened" in my bittorrent client.

    mmh?!
    Post edited by itorshopmap on
  • In case you're planning to run through this process "by hand," as it were, here are the Mac terminal scripts to accomplish rcbarnes' steps:

    On your Mac, do:

    # Set up a client ID and tuck it in a file in your home directory
    head -n 100 /dev/urandom | md5 > ~/.pia_client_id

    # Detect (and save) your tunnel's IP address, needed for building the URL to POST 
    ifconfig tun0 | grep "inet " | cut -d\  -f2|tee /tmp/vpn_ip

    # Detect (and save) your world-visible IP (bit of a cheat, relies on an outside lookup)
    curl ifconfig.me/ip|tee /tmp/vpn_external_ip

    The final command to set and return the forwarded port number looks like this:

    curl -d "user=USERNAME&pass=PASSWORD&client_id=$(cat ~/.pia_client_id)&local_ip=$(cat /tmp/vpn_ip)" https://www.privateinternetaccess.com/vpninfo/port_forward_assignment

    You should be able to use the returned port to manually configure a forward through your router to your specific Mac's local (LAN) IP address and set the peer listening port in your BT client (Transmission, for example). Clunky, and it only works until the VPN tunnel closes (you have to re-do the whole process every time you reconnect), but it should work.
  • edited September 2012 Posts: 10
    @ Disposable001

    thanks ;)  i've done it manually and the reported port from the terminal output is accepted by transmission as an opened port.

    in my previous attempts i was confused becaus i got no output for the pia_client_id command and in my home directory, nevertheless the manual steps seem to be successful.

    since i have a nice little applescript to start transmission which binds the current local vpn ip to the transmission application it would be handy to add the port forwarding. 

    i am trying to figure out how to do the curl command in applescript


    Post edited by itorshopmap on
  • See http://www.cyberciti.biz/faq/mac-osx-applescript-run-shell-script/
    do shell script "command"
    do shell script "command1; command2"
    set variableName to do shell script "command"
    set variableName to do shell script "command1; command2"
    do shell script "/path/to/yourscript.sh"
    do shell script "/bin/tcsh /path/to/yourscript.csh"
    do shell script "/bin/tcsh -c 'command1'"
  • when i do this:


    do shell script "curl -d 'user=USERNAMEpass=PASSWORD&client_id=$(cat ~/.pia_client_id)&local_ip=LOCAL_IP' https://www.privateinternetaccess.com/vpninfo/port_forward_assignment"


    i get a port prompted in the applescript editor. it differs from running the command directly in the terminal 


    curl -d "user=USERNAMEpass=PASSWORD&client_id=$(cat ~/.pia_client_id)&local_ip=LOCAL_IP" https://www.privateinternetaccess.com/vpninfo/port_forward_assignment


     i get the "correct" one. the problem is somehow with the quotation marks of the original curl command in the applescript editor

  • Try using \" (backslash double-quote) instead of '

    Single quotes will stop the shell from expanding the embedded commands/variables - they will be interpreted as literal strings instead.
  • Bingo. Mezzanine's right. Make the innermost quotes into \" literals.
  • edited September 2012 Posts: 10
    @Mezzanine thanks for the tip

    this is currently what i came up with in order to get the forwarded port automatically to the transmission app.

    set vpn_ip to do shell script "ifconfig tun0 | grep inet | awk '{print $2}'"

    set vpn_port to do shell script "curl -d \"user=USERNAMEpass=PASSWORD&client_id=$(cat ~/.pia_client_id)&local_ip=" & vpn_ip & "\" https://www.privateinternetaccess.com/vpninfo/port_forward_assignment 2>/dev/null|grep -oE \"[0-9]+\""


    do shell script "defaults delete org.m0k.transmission BindPort"

    do shell script "defaults write org.m0k.transmission BindPort " & vpn_port & ""

    Post edited by itorshopmap on
  • Nice. I didn't know you could push the Transmission config from a shell script. That'll be handy.
  • i used this little trick for binding the vpn connection to transmission

    set vpn_ip to do shell script "ifconfig tun0 | grep inet | awk '{print $2}'" # get current ip of vpn interface

    do shell script "defaults delete org.m0k.transmission BindAddressIPv4" #delete previously written ipv4binding value

    do shell script "defaults write org.m0k.transmission BindAddressIPv4 " & vpn_ip & "" #write current vpn ip into transmission.plist


    and now added the port forwarding ;)


    put all that in a applescript, save as application and then use it to start transmission... voila


    vpn ip & vpn port bound to transmission 




  • Does UP&P in Transmission configure the port fwd on the router for you, then?
  • edited September 2012 Posts: 10

    no, the UPnP and NAT-PMP is off in the transmission preferences. 

    "randomize port on launch" and "automatically map port" are unchecked

    but the value written with the shell script is now shown correctly in the "listening port" box

    i use an apple time capsule as my router, but i haven't configured any port forwarding with the airport utility program. only the option "nat port mapping" is checked, but that was my previous setting before using vpn service.

    with the current procedure i get the "green light" with the manually/semi automatically forwarded port an the applescript shenanigans ;).  


    p.s. 

    for the heck of it, i just checked the box "automatically map port". seems to be working fine, but most of the time i am the only one with a running bit torrent client on my network.
    Post edited by itorshopmap on
  • edited September 2012 Posts: 15
    So, for Mac users with Viscosity and Transmission, here it is all in one script:

    # Set up a client ID and tuck it in a file in your home directory

    # NOTE: Only do this once, to create the initial file, PIA wants us to reuse this value

    # head -n 100 /dev/urandom | md5 > ~/.pia_client_id


    # Substitue USERNAME and PASSWORD with your own account info in the command below

    set vpn_ip to do shell script "ifconfig tun0 | grep inet | awk '{print $2}'" # get current ip of vpn interface

    set vpn_port to do shell script "curl -d \"user=USERNAME&pass=PASSWORD&client_id=$(cat ~/.pia_client_id)&local_ip=" & vpn_ip & "\" https://www.privateinternetaccess.com/vpninfo/port_forward_assignment 2>/dev/null|grep -oE \"[0-9]+\""

    do shell script "defaults delete org.m0k.transmission BindPort" # delete previous port value

    do shell script "defaults write org.m0k.transmission BindPort " & vpn_port & ""

    do shell script "defaults delete org.m0k.transmission BindAddressIPv4" #delete previously written ipv4binding value

    do shell script "defaults write org.m0k.transmission BindAddressIPv4 " & vpn_ip & "" #write current vpn ip into transmission.plist
















    Save this as an AppleScript and use Viscosity to run it when the VPN tunnel is established. Configure Transmission with "randomize port on launch" UNchecked and "automatically map port" checked in the Network preferences.


    Post edited by Disposable001 on
  • Getting 500 Internal Server Error when presenting the URL as indicated above. Here's an ASCII trace of the curl session I've been trying to do. (U & P have been stripped out, I'm not actually using the strings USERNAME and PASSWORD ;)


    curl --trace-ascii /dev/stdout -d user=USERNAME -d pass=PASSWORD -d client_id=$(cat ~/.pia_client_id) -d local_ip=$(cat /tmp/vpn_ip) --url https://www.privateinternetaccess.com/vpninfo/port_forward_assignment
    == Info: About to connect() to www.privateinternetaccess.com port 443 (#0)
    == Info:   Trying 173.255.233.20...
    == Info: connected
    == Info: Connected to www.privateinternetaccess.com (173.255.233.20) port 443 (#0)
    == Info: SSLv3, TLS handshake, Client hello (1):
    => Send SSL data, 130 bytes (0x82)

    -- Snipped several bytes of certificate data --

    == Info: SSLv3, TLS change cipher, Client hello (1):
    => Send SSL data, 1 bytes (0x1)
    0000: .
    == Info: SSLv3, TLS handshake, Finished (20):
    => Send SSL data, 16 bytes (0x10)
    0000: .....l...}....Kb
    == Info: SSLv3, TLS change cipher, Client hello (1):
    <= Recv SSL data, 1 bytes (0x1)
    0000: .
    == Info: SSLv3, TLS handshake, Finished (20):
    <= Recv SSL data, 16 bytes (0x10)
    0000: ......B..T.:.p.D
    == Info: SSL connection using DHE-RSA-AES256-SHA
    == Info: Server certificate:
    == Info: subject: O=*.privateinternetaccess.com; OU=Domain Control Validated; CN=*.privateinternetaccess.com
    == Info: start date: 2012-09-11 21:27:59 GMT
    == Info: expire date: 2013-09-11 21:27:59 GMT
    == Info: subjectAltName: www.privateinternetaccess.com matched
    == Info: issuer: C=US; ST=Arizona; L=Scottsdale; O=GoDaddy.com, Inc.; OU=http://certificates.godaddy.com/repository; CN=Go Daddy Secure Certification Authority; serialNumber=07969287
    == Info: SSL certificate verify ok.
    => Send header, 261 bytes (0x105)
    0000: POST /vpninfo/port_forward_assignment HTTP/1.1
    0030: User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0
    0070:  OpenSSL/0.9.8r zlib/1.2.5
    008c: Host: www.privateinternetaccess.com
    00b1: Accept: */*
    00be: Content-Length: 91
    00d2: Content-Type: application/x-www-form-urlencoded
    0103: 
    => Send data, 91 bytes (0x5b)
    0000: user=USERNAME&pass=PASSWORD&client_id=671d328d3d29efcf451cc6ed3ff
    0040: 47210&local_ip=10.102.20.10
    == Info: upload completely sent off: 91 out of 91 bytes
    <= Recv header, 36 bytes (0x24)
    0000: HTTP/1.1 500 Internal Server Error
    <= Recv header, 37 bytes (0x25)
    0000: Date: Wed, 19 Sep 2012 15:18:32 GMT
    <= Recv header, 32 bytes (0x20)
    0000: Server: Apache/2.2.16 (Ubuntu)
    <= Recv header, 61 bytes (0x3d)
    0000: X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.11
    <= Recv header, 48 bytes (0x30)
    0000: X-Request-Id: 01f6894a8b10de0552355693b2f80d0a
    <= Recv header, 21 bytes (0x15)
    0000: X-Runtime: 0.864596
    <= Recv header, 32 bytes (0x20)
    0000: X-Rack-Cache: invalidate, pass
    <= Recv header, 19 bytes (0x13)
    0000: Content-Length: 0
    <= Recv header, 13 bytes (0xd)
    0000: Status: 500
    <= Recv header, 23 bytes (0x17)
    0000: Vary: Accept-Encoding
    <= Recv header, 19 bytes (0x13)
    0000: Connection: close
    <= Recv header, 40 bytes (0x28)
    0000: Content-Type: text/html; charset=utf-8
    <= Recv header, 2 bytes (0x2)
    0000: 
    == Info: Closing connection #0
    == Info: SSLv3, TLS alert, Client hello (1):
    => Send SSL data, 2 bytes (0x2)
    0000: ..

  • hello,

    for additional growl notification for the above script . Analog to the above script. Save as script and run it after established vpn connection.





    tell application "Growl" #getting growl to display the succeeful outcome 

    set the allNotificationsList to {"IPv4 Binding"}

    set the enabledNotificationsList to {"IPv4 Binding"}

    register as application "IPv4 Binding" all notifications allNotificationsList default notifications enabledNotificationsList

    notify with name "IPv4 Binding" title "IPv4 Binding" description ip4binding application name ¬

    "IPv4 Binding" icon of application "Transmission.app"

    end tell


    tell application "Growl" #getting growl to display the succeeful outcome 

    set the allNotificationsList to {"Port Binding"}

    set the enabledNotificationsList to {"Port Binding"}

    register as application "Port Binding" all notifications allNotificationsList default notifications enabledNotificationsList

    notify with name "Port Binding" title "Port Binding" description vpn_port application name ¬

    "Port Binding" icon of application "Transmission.app"

    end tell


    So, for Mac users with Viscosity and Transmission, here it is all in one script:

    # Set up a client ID and tuck it in a file in your home directory

    # NOTE: Only do this once, to create the initial file, PIA wants us to reuse this value

    # head -n 100 /dev/urandom | md5 > ~/.pia_client_id


    # Substitue USERNAME and PASSWORD with your own account info in the command below

    set vpn_ip to do shell script "ifconfig tun0 | grep inet | awk '{print $2}'" # get current ip of vpn interface......


  • edited September 2012 Posts: 1





    Here's a Python script I use under Windows and works like a charm for me:





    import re
    import random
    import urllib
    import socket
    import string

    user = '<username>'
    pw = '<pw>'
    local_ip = socket.gethostbyname(socket.gethostname())
    pia_client_id = "".join( [random.choice(string.letters) for i in xrange(32)] )
    data = {'user': user, 'pass': pw, 'client_id': pia_client_id, 'local_ip': local_ip }
    params = urllib.urlencode(data)
    answer = urllib.urlopen('https://www.privateinternetaccess.com/vpninfo/port_forward_assignment', params).read()
    m = re.search('(\d+)', answer)
    print m.group(1)

    Post edited by baderj on
  • I am curious about the specific server-side uses of the pseudorandom string we're keeping as a long-term token.  Does changing the string change the port we are assigned?  It is deterministically mapped, or would changing our seed then reverting just give a random new port? 

    I know these are shared IPs, but is there any chance we could eventually make a handful of requests with a small set of randomizer strings (instead of only one such string per system now), in order to open up multiple port forwarding s?  The unprivileged ports (or even just the high-numbered ports for short-lived connections) number in the tens of thousands so I hope they are not a scant resource. :-P

    I ask because with only one, I have to select a single one of my desktop's services to enable at a time when on the VPN, but that means seeding and backing up my system are mutually exclusive, not to mention blocking inbound SSH connections (which I use very regularly) if I forget to switch back to that before I leave my apartment.

    In short: the new port forwarding mechanism is awesome, thanks!  (And can we eventually use it to open a few more application's inbound ports?)
  • On a possibly related note, I've been playing with this for a few days on at least a couple of machines, so I'm sure I haven't used the same client_id string every time. I'm still getting a 500 Internal Server Error in response to queries, rather than the JSON response I'd expect. Is my account somehow bound to that initial MD5 has string I created? (If so, uh-oh...)
  • Bump! Hey, Support, is any API documentation or debugging info related to the Internal Server Error forthcoming? Thanks!
  • Posts: 162
    Disposable001, sorry about that!  The developers are applying more meaningful error responses.

  • Hi, don't want to hi-jack the threa, but is it possible to get a script to use with Tomato firmware, to use PIA portforwarding?

    Thanks in advance,

    K1ngF1sher
  • Thanks, Support. I'll stay tuned.
  • I still have one question:

    how often do I need to post that command? Every time I connect to the vpn or just once per server or what ever?

    Thanks already :)
  • Posts: 162
    Once per hour Coxeroni :)
  • Once per hour Coxeroni :)
    Seriously? Why is that?
  • edited September 2012 Posts: 1
    I successfully get a response port, but any test I do to confirm the port is open externally fails. Any reason why this might be?

    To clarify, I am using openvpn on linux and connecting to the ca.privateinternetacess.com endpoint.
    Post edited by the_dalai_lama on
  • well, it looks that port 22 and 80 is let through by VPN provider by default. So if you are not blocking it, go for port 80, and don't need to play with 
Sign In or Register to comment.