2

Netgear R7000 Router Tomato v1.28.0000 -2017.2-kille72- K26ARM USB AIO-64K

I could do with some help debugging my script.

Goal: retrieve forwarded port number from VPN API JSON, pass port number to running transmission daemon using transmission-remote.

My input:

#!/opt/bin/bash
#
# Enable port forwarding when using Private Internet Access
#
# Usage:
#  ./port_forwarding.sh
set -x
exec 5>/etc/openvpn/mylog
BASH_XTRACEFD="5"
PS4='$LINENO: '

TRANSUSER=me
TRANSPASS=mypass
TRANSHOST=192.168.1.251

/bin/echo waiting 20s for vpn to connect and trasmission to start
sleep 20

error( )
{
  /bin/echo "$@" 1>&2
  exit 1
}

error_and_usage( )
{
  /bin/echo "$@" 1>&2
  usage_and_exit 1
}

usage( )
{
  /bin/echo "Usage: `dirname $0`/$PROGRAM"
}

usage_and_exit( )
{
  usage
  exit $1
}

version( )
{
  /bin/echo "$PROGRAM version $VERSION"
}


port_forward_assignment( )
{
  client_id_file="/etc/openvpn/pia_client_id"
  if [ ! -f "$client_id_file" ]; then
    if hash /opt/bin/shasum 2>/dev/null; then
      /usr/bin/head -n 100 /dev/urandom | /opt/bin/shasum -a 256 | tr -d " -" > "$client_id_file"
    elif hash /opt/bin/sha256sum 2>/dev/null; then
      /usr/bin/head -n 100 /dev/urandom | /opt/bin/sha256sum | tr -d " -" > "$client_id_file"
    else
      /bin/echo "Please install shasum or sha256sum, and make sure it is visible in your \$PATH"
      exit 1
    fi
  fi
  client_id=`/bin/cat "$client_id_file"`
  json=`/opt/bin/curl "http://209.222.18.222:2000/?client_id=$client_id" 2>/dev/null`
  if [ "$json" == "" ]; then
    json='Port forwarding is already activated on this connection, has expired, or you are not connected to a PIA region that supports port forwarding'
  fi

  /bin/echo server returned message: $json

#trim VPN forwarded port from JSON
PORT=$(echo $json | /usr/bin/awk 'BEGIN{r=1;FS="[{}\":]+"} /port/{r=0; print $3} END{exit r}')
/bin/echo if succesful port is:$PORT  

#change transmission port on the fly

/opt/bin/transmission-remote $TRANSHOST --auth $TRANSUSER:$TRANSPASS -p "$PORT"
/bin/echo your transmission details: $TRANSHOST $TRANSUSER $TRANSPASS
}

/bin/echo remember to reconnect to VPN before running this script. Run no longer than 2 minutes after connection or this will fail!

EXITCODE=0
PROGRAM=`basename $0`
VERSION=2.1

while /usr/bin/test $# -gt 0
do
  case $1 in
  --usage | --help | -h )
    usage_and_exit 0
    ;;
  --version | -v )
    version
    exit 0
    ;;
  *)
    error_and_usage "Unrecognised option: $1"
    ;;
  esac
  shift
done

port_forward_assignment

exit 0

Problem: When I run this script from shell it works fine, but when I call the script in my openvpn config I get this result:

+ PS4='$LINENO: '
12: TRANSUSER=me
13: TRANSPASS=mypass
14: TRANSHOST=192.168.1.251
16: /bin/echo waiting 20s for vpn to connect and trasmission to start
17: sleep 20
79: /bin/echo remember to reconnect to VPN before running this script. Run no longer than 2 minutes after connection or this will 'fail!'
81: EXITCODE=0
882: basename /etc/openvpn/test.sh
82: PROGRAM=test.sh
83: VERSION=2.1
85: /usr/bin/test 1 -gt 0
87: case $1 in
96: error_and_usage 'Unrecognized option: [AF_INET]45.136.190.211 1198'
27: /bin/echo 'Unrecognized option: [AF_INET]46.136.190.211 1198'
28: usage_and_exit 1
38: usage
333: dirname /etc/openvpn/test.sh
33: /bin/echo 'Usage: /etc/openvpn/test.sh'
39: exit 1

Works fine when run in shell though:

+ PS4='$LINENO: '
12: TRANSUSER=me
13: TRANSPASS=mypass
14: TRANSHOST=192.168.1.251
16: /bin/echo waiting 20s for vpn to connect and trasmission to start
17: sleep 20
79: /bin/echo remember to reconnect to VPN before running this script. Run no longer than 2 minutes after connection or this will 'fail!'
81: EXITCODE=0
882: basename ./test.sh
82: PROGRAM=test.sh
83: VERSION=2.1
85: /usr/bin/test 0 -gt 0
102: port_forward_assignment
50: client_id_file=/etc/openvpn/pia_client_id
51: '[' '!' -f /etc/openvpn/pia_client_id ']'
661: /bin/cat /etc/openvpn/pia_client_id
61: client_id=080db0a6e936918d405683447a78bf426223e9a1ea2ecce744722ac3241d4232
662: /opt/bin/curl 'http://209.222.18.222:2000/?client_id=080db0a6e936918d405683447a78bf426273e9a1ea2ecce744722ac3241d4232'
62: json='{"port":44257}'
63: '[' '{"port":44257}' == '' ']'
67: /bin/echo server returned message: '{"port":44257}'
770: echo '{"port":44257}'
770: /usr/bin/awk 'BEGIN{r=1;FS="[{}\":]+"} /port/{r=0; print $3} END{exit r}'
70: PORT=44257
71: /bin/echo if successful port is:44257
75: /opt/bin/transmission-remote 192.168.1.251 --auth me:mypass -p 44257
76: /bin/echo your transmission details: 192.168.1.251 me mypass
104: exit 0

Where am I going wrong? Why does this fail when script is called by OpenVPN and not when I run in shell? How can I find out what AF_INET points too? Strangely the IP address in the error is my client VPN server and port, not the forwarded port number returned from the JSON.

My OpenVPN config:

# Automatically generated configuration
daemon
client
dev tun11
proto udp
remote nl.privateinternetaccess.com 1198
resolv-retry 30
nobind
persist-key
persist-tun
comp-lzo adaptive
ncp-ciphers AES-128-GCM:AES-256-GCM:AES-128-CBC:AES-256-CBC
cipher AES-128-CBC
redirect-gateway def1
verb 3
script-security 2
up updown.sh
down updown.sh
ca ca.crt
status-version 2
status status

# Custom Configuration
syslog [progname]
persist-key
persist-tun
tls-client
auth-user-pass /tmp/password.txt
comp-lzo
verb 3
reneg-sec 0
ipchange "/etc/openvpn/test.sh"
script-security 3

EDIT#

Thanks to Ipor Sircer below I managed to avoid the error by not defining argument 1. My input now looks like this (for simplication) but my output when called by OpenVPN is very different than when I run the script directly.

My input:

#!/opt/bin/bash
#
# Enable port forwarding when using Private Internet Access
#
# Usage:
#  ./port_forwarding.sh
set -x
exec 5>/etc/openvpn/mylog
BASH_XTRACEFD="5"
PS4='$LINENO: '

TRANSUSER=me
TRANSPASS=mypass
TRANSHOST=192.168.1.251

  client_id_file="/etc/openvpn/pia_client_id"
  if [ ! -f "$client_id_file" ]; then
    if hash /opt/bin/shasum 2>/dev/null; then
      /usr/bin/head -n 100 /dev/urandom | /opt/bin/shasum -a 256 | tr -d " -" > "$client_id_file"
    elif hash /opt/bin/sha256sum 2>/dev/null; then
      /usr/bin/head -n 100 /dev/urandom | /opt/bin/sha256sum | tr -d " -" > "$client_id_file"
    else
      /bin/echo "Please install shasum or sha256sum, and make sure it is visible in your \$PATH"
      exit 1
    fi
  fi
  client_id=`/bin/cat "$client_id_file"`
  json=`/opt/bin/curl "http://209.222.18.222:2000/?client_id=$client_id" 2>/dev/null`
  if [ "$json" == "" ]; then
    json='Port forwarding is already activated on this connection, has expired, or you are not connected to a PIA region that supports port forwarding'
  fi

  /bin/echo server returned message: $json

#trim VPN forwarded port from JSON
PORT=$(echo $json | /usr/bin/awk 'BEGIN{r=1;FS="[{}\":]+"} /port/{r=0; print $3} END{exit r}')
/bin/echo if successful port is:$PORT  

#change transmission port on the fly

/opt/bin/transmission-remote $TRANSHOST --auth $TRANSUSER:$TRANSPASS -p "$PORT"
/bin/echo your transmission details: $TRANSHOST $TRANSUSER $TRANSPASS

Output with OpenVPN:

+ PS4='$LINENO: '
12: TRANSUSER=me
13: TRANSPASS=pass
14: TRANSHOST=192.168.1.251
16: client_id_file=/etc/openvpn/pia_client_id
17: '[' '!' -f /etc/openvpn/pia_client_id ']'
227: /bin/cat /etc/openvpn/pia_client_id
27: client_id=080db0a6e936918d405683447a78bf426273e9a1ea2ecce744722ac3241d4232
228: /opt/bin/curl 'http://209.222.18.222:2000/?client_id=080db0a6e936918d405683447a78bf426273e9a1ea2ecce744722ac3241d4232'
28: json=
29: '[' '' == '' ']'
30: json='Port forwarding is already activated on this connection, has expired, or you are not connected to a PIA region that supports port forwarding'
33: /bin/echo server returned message: Port forwarding is already activated on this connection, has expired, or you are not connected to a PIA region that supports port forwarding
336: echo Port forwarding is already activated on this connection, has expired, or you are not connected to a PIA region that supports port forwarding
336: /usr/bin/awk 'BEGIN{r=1;FS="[{}\":]+"} /port/{r=0; print $3} END{exit r}'
36: PORT=
37: /bin/echo if successful port is:
41: /opt/bin/transmission-remote 192.168.1.251 --auth me:pass -p ''
42: /bin/echo your transmission details: 192.168.1.251 me pass

Without OpenVPN:

16: client_id_file=/etc/openvpn/pia_client_id
17: '[' '!' -f /etc/openvpn/pia_client_id ']'
227: /bin/cat /etc/openvpn/pia_client_id
27: client_id=080db0a6e936918d405683447a78bf426273e9a1ea2ecce744722ac3241d4232
228: /opt/bin/curl 'http://209.222.18.222:2000/?client_id=080db0a6e936918d405683447a78bf426273e9a1ea2ecce744722ac3241d4232'
28: json='{"port":44257}'
29: '[' '{"port":44257}' == '' ']'
33: /bin/echo server returned message: '{"port":44257}'
336: echo '{"port":44257}'
336: /usr/bin/awk 'BEGIN{r=1;FS="[{}\":]+"} /port/{r=0; print $3} END{exit r}'
36: PORT=44257
37: /bin/echo if successful port is:44257
2

Openvpn call your script with 2 parameters which you've defined as unrecognized option.

man openvpn:

"--ipchange cmd

Run command cmd when our remote ip-address is initially authen‐ ticated or changes.

cmd consists of a path to script (or executable program), optionally followed by arguments. The path and arguments may be single- or double-quoted and/or escaped using a backslash, and should be separated by one or more spaces.

When cmd is executed two arguments are appended after any arguments specified in cmd, as follows:

cmd ip_address port_number"

  • thank you so much! I wrongly assumed there were no arguments passed, the same as the up and down commands. – Dodgexander Oct 27 '17 at 20:52
  • Problem I am having now is the line: json=/opt/bin/curl "http://209.222.18.222:2000/?client_id=$client_id" 2>/dev/null is working fine to retrieve the port number from JSON but not when the script is called by openVPN. How can I debug this? – Dodgexander Oct 27 '17 at 21:38
  • I provided the answer to your JSON problem but a moderator deleted it. – dotvotdot Nov 19 '17 at 16:26
0

The reason that json is empty is because curl fails.

The reason that curl fails is because; as a security measure (therefore by design), OpenVPN will not allow any packets to traverse the tunnel while any script which was started by the openvpn binary is still executing.

You will need to find another method to invoke your script.

This is why this is the correct answer and why this answer should not be deleted:

The client is connecting to remote nl.privateinternetaccess.com 1198

VPN Service provider servers typically redirect all traffic over the VPN.

In the --ipchange script we find this command: json=`/opt/bin/curl "http://209.222.18.222:2000/?client_id=$client_id" 2>/dev/null`

Therefore: curl http://209.222.18.222:2000 etc is trying to use the VPN to connect to IP 209.222.18.222 and openvpn will not allow any packets to pass over the VPN until all scripts have completed.

This has also been asked and answered @ https://forums.openvpn.net/viewtopic.php?f=15&t=25114#p73956

Note: I have gone to great lengths to verify that this answer is accurate while https://unix.stackexchange.com/users/257736/dodgexander has not responded to any of the answers received here or at openvpn.net

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.