Invalid preceding regex

0

I receive error:

awk: bad regex '{|:|}': Invalid preceding regular expression {"arguments":{},"result":"success"} {"port":37482}

Which I believe is related to this line:

PORT=$(echo $json | awk 'BEGIN{r=1;FS="{|:|}"} /port/{r=0; print $3} END{exit r}')
#echo $PORT

Does anyone know what it means and how I can fix it? I am new to scripting but as I understand it the expression |:| is incorrect. $json is a file I am pulling from my VPN with port information for forwarding.

My input:

#!/usr/bin/env bash
#
# Enable port forwarding when using Private Internet Access
#
# Usage:
#  ./port_forwarding.sh
TRANSUSER=xxx
TRANSPASS=xxxx
TRANSHOST=localhost
error( )
{
  echo "$@" 1>&2
  exit 1
}
error_and_usage( )
{
  echo "$@" 1>&2
  usage_and_exit 1
}
usage( )
{
  echo "Usage: `dirname $0`/$PROGRAM"
}
usage_and_exit( )
{
  usage
  exit $1
}
version( )
{
  echo "$PROGRAM version $VERSION"
}

port_forward_assignment( )
{
  client_id_file="/etc/openvpn/pia_client_id"
  if [ ! -f "$client_id_file" ]; then
    if hash shasum 2>/dev/null; then
      head -n 100 /dev/urandom | shasum -a 256 | tr -d " -" > "$client_id_file"
    elif hash sha256sum 2>/dev/null; then
      head -n 100 /dev/urandom | sha256sum | tr -d " -" > "$client_id_file"
    else
      echo "Please install shasum or sha256sum, and make sure it is visible in your \$PATH"
      exit 1
    fi
  fi
  client_id=`cat "$client_id_file"`
  json=`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
  echo $json
}
#trim VPN forwarded port from JSON
PORT=$(echo $json | awk 'BEGIN{r=1;FS="{|:|}"} /port/{r=0; print $3} END{exit r}')
#echo $PORT
#change transmission port on the fly
CURLOUT=$(curl -u $TRANSUSER:$TRANSPASS ${TRANSHOST}:9091/transmission/rpc 2>/dev/null)
REGEX='X-Transmission-Session-Id\: (\w*)'

if [[ $CURLOUT =~ $REGEX ]]; then
    SESSIONID=${BASH_REMATCH[1]}
else
    exit 1
fi
DATA='{"method": "session-set", "arguments": { "peer-port" :'$port' } }'

curl -u $TRANSUSER:$TRANSPASS http://${TRANSHOST}:9091/transmission/rpc -d "$DATA" -H "X-Transmission-Session-Id: $SESSIONID"

EXITCODE=0
PROGRAM=`basename $0`
VERSION=2.1
while test $# -gt 0
do
  case $1 in
  --usage | --help | -h )
    usage_and_exit 0
    ;;
  --version | -v )
    version
    exit 0
    ;;
  *)
    error_and_usage "Unrecognized option: $1"
    ;;
  esac
  shift
done
port_forward_assignment
exit 0

The script is taken from: https://www.privateinternetaccess.com/forum/discussion/23431/new-pia-port-forwarding-api/p3?

It is designed to make a request to their API for a port number and then to forward that port received into transmission daemon.

Dodgexander

Posted 2017-10-18T21:32:39.293

Reputation: 1

What are you trying to accomplish? What is your input, what is your desired output? If you have some input JSON, then post it. If you are trying to retrieve the port number from the JSON, then say so. Try not to ask an XY problem https://meta.stackexchange.com/a/66378/364309

– Attie – 2017-10-18T21:38:45.227

I did ask previously here but didn't receive any answers. I thought because I made the question too specific! https://superuser.com/questions/1258891/tomato-transmission-openvpn-and-port-forwarding

– Dodgexander – 2017-10-19T00:11:28.203

Sorry for being a noob but I am trying to learn how I can take the port number from the json and then read the given port number so I can forward it to transmission. I understand the json returns the port, but I am not sure how, nor how to take that port and insert it into transmission – Dodgexander – 2017-10-19T23:51:42.893

Answers

2

If you are asking "How can I get the port number from this input data?", with the following data:

{"arguments":{},"result":"success"} {"port":37482}

Then I'd advise you look at jq:

$ echo '{"arguments":{},"result":"success"} {"port":37482}' | jq -s '.[1].port'
37482

jq -s will "slurp" the input into an array, this is necessary as you are providing two distinct objects:

$ echo '{"arguments":{},"result":"success"} {"port":37482}' | jq -s '.'
[
  {
    "arguments": {},
    "result": "success"
  },
  {
    "port": 37482
  }
]

You must then address the second element of the array (.[1]), and subsequently the 'port' element (.[1].port).


As an extension to address some of your further questions:

You do know what the JSON is, you grab it here, and could easily print it, redirect it to a file, etc...

client_id=$(cat "$client_id_file")
curl "http://209.222.18.222:2000/?client_id=$client_id" > EXAMPLE.json

I've identified a method to extract the port number above, but if you can't / don't want to use jq, then python would work nicely, but unfortunately your input appears to be not-quite-JSON, so we need to work a bit harder:

Note: we need to pass the JSON in as the first argument, as the script is going in via stdin, so the echo xxx | jq approach above won't work nicely.

$ python - <<"EOF" '{"arguments":{},"result":"success"} {"port":37482}'
def read_obj(filename):
    from sys import argv
    from json import JSONDecoder
    decoder = JSONDecoder()
    file_content = argv[1].lstrip()
    while file_content:
        obj, eod = decoder.raw_decode(file_content)
        file_content = file_content[eod:].lstrip()
        yield obj

x = read_obj('x')
obj = next(x) # discard the first object
obj = next(x) # use the second object
print(obj['port'])
EOF

I can't help you interface with transmission.

Attie

Posted 2017-10-18T21:32:39.293

Reputation: 14 841

thanks! I'm not sure how I can install jq on my system, I am running tomato on a router, the only repository I have access too is optware. – Dodgexander – 2017-10-19T00:23:35.880

You could build it from source =) – Attie – 2017-10-19T12:03:08.643

I don't really know what the output data from json is, I know the json returns the port number but how can I find how to pull the port number from the json? Here is the port forwarding API: https://www.privateinternetaccess.com/forum/discussion/23431/new-pia-port-forwarding-api/p1

– Dodgexander – 2017-10-19T23:48:52.207

Thanks for this info. I think I worked out how to do it, I added my answer. I found the easiest way after trimming the json was to pass the port number as a variable to a package named transmission remote that is designed to interact with the running daemon. I actually tried compiling jq but I couldn't due to an error. The new gcc version I was using didn't support the -qversion parameter. In the end I found the json was returning port:numberofport. After correcting my awk line it was successfully trimming it and passing it as the variable $port that I then passed to transmission remote! – Dodgexander – 2017-10-21T04:25:01.317

Thanks very much for your help, I've learnt a lot, plus I don't want to end it here, I'd like to tidy the script to make it more user friendly. It may be my first script, most of which I copied from elsewhere but it's very rudimental! – Dodgexander – 2017-10-21T04:30:17.393

0

Success! Working script below:

Dependencies: transmission-remote - you can install the transmission-remote-openssl package through optware. sha256sum - optware package coreutils-sha256sum

#!/usr/bin/env bash
#
# Enable port forwarding when using Private Internet Access
#
# Usage:
#  ./port_forwarding.sh
# script must be run within 2 mins of connecting to vpn server. Do not forget to reconnect/connect
# fill in your transmission username, password and hostname/ip below:

TRANSUSER=xxxxx
TRANSPASS=xxxxx
TRANSHOST=localhost
#now let the script do the work

Sleep 20
echo pausing to wait for vpn to connect and transmission to start

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

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

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

usage_and_exit( )
{
  usage
  exit $1
}

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


port_forward_assignment( )
{
  client_id_file="/etc/openvpn/pia_client_id"
  if [ ! -f "$client_id_file" ]; then
    if hash shasum 2>/dev/null; then
      head -n 100 /dev/urandom | shasum -a 256 | tr -d " -" > "$client_id_file"
    elif hash sha256sum 2>/dev/null; then
      head -n 100 /dev/urandom | sha256sum | tr -d " -" > "$client_id_file"
    else
      echo "Please install shasum or sha256sum, and make sure it is visible in your \$PATH"
      exit 1
    fi
  fi
  client_id=`cat "$client_id_file"`
  json=`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

  echo server returned: $json

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

#change transmission port on the fly

transmission-remote $TRANSHOST --auth $TRANSUSER:$TRANSPASS -p "$PORT"
echo here are your transmission credentials: host:$TRANSHOST username:$TRANSUSER password:$TRANSPASS
}
echo remember to run no longer than 2 mins after reconnecting/connecting to vpn server.

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

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

port_forward_assignment

exit 0

Dodgexander

Posted 2017-10-18T21:32:39.293

Reputation: 1