Code: Select all
#!/usr/bin/python3
import os
import subprocess
from os.path import expanduser
import json
import time
import shutil
# Simple function to read variables from secret file
def read_secrets(config=expanduser("~")+'/.local/share/ngrok/secrets.ini'):
from configparser import ConfigParser
secrets_object = ConfigParser(
interpolation=None, inline_comment_prefixes='#')
secrets_object.optionxform = str
with open(config) as f:
secrets_object.read_file(f)
return secrets_object._sections['secrets']
# Obtain endpoint hostport from ngrok api and connect to remote host via ssh
def connect_remote(username, api_key, local_forward_list):
curl_path = shutil.which("curl")
if not curl_path:
print("curl not found, exiting")
return 0
ssh_path = shutil.which("ssh")
if not ssh_path:
print("ssh not found, exiting")
return 0
# setup curl request command string:
curl_cmd = curl_path+''' \
-H "Authorization: Bearer '''+api_key+'''" \
-H "Ngrok-Version: 2" \
https://api.ngrok.com/endpoints
'''
# send ngrok api request
ngrok_result = subprocess.check_output(curl_cmd, shell=True)
# parse json
ngrok_json = json.loads(ngrok_result)
# obtain hostport value
hostport = ngrok_json['endpoints'][0]['hostport'].split(':')
if not hostport:
print('no hostport object')
return 0
hostname = hostport[0]
port = hostport[1]
# add list of local forward parameters from secrets
local_forward_str = ''
for forward in local_forward_list:
local_forward_str += ' -L '+forward
ssh_cmd = ssh_path+' -p '+port+' -o StrictHostKeyChecking=no '+local_forward_str+' '+username+'@'+hostname
#invoke remote shell via ngrok tunnel
return os.system(ssh_cmd)
# main function
secrets = read_secrets()
username = secrets.get('REMOTE_USERNAME')
api_key = secrets.get('NGROK_API_KEY')
local_forward_list = json.loads(secrets.get('LOCAL_FORWARD'))
# connect and resume connection after sleep or connection errors
while(True):
result = connect_remote(username, api_key, local_forward_list)
print("ssh return code:",result)
exit_codes = [0,1,2,65,71,75,77,78,79]
# exit if ssh code is success or not related to connection errors
if result in exit_codes:
quit()
# sleep for 2 seconds and retry connection
time.sleep(2)
Sample secrets.ini file, located at ~/.local/share/ngrok/secrets.ini
Code: Select all
[secrets]
REMOTE_USERNAME={USERNAME}
NGROK_API_KEY={NGROK_API_KEY}
# local forward format is LOCAL_PORT:REMOTE_IP:REMOTE_PORT
LOCAL_FORWARD=[
"8280:192.168.2.1:80",
"8122:192.168.1.1:22"
]