Skip to content

Commit

Permalink
allow executing user defined script
Browse files Browse the repository at this point in the history
  • Loading branch information
Dragon2fly committed Dec 10, 2016
1 parent 50f92e8 commit 6cf0821
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 74 deletions.
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ VPN GATE client for linux
* Be able to connect to open vpn servers at **http://www.vpngate.net/en/** directly or through proxy
* Auto add DNS to fix DNS leak.
* Auto filter out dead VPN servers. (updated on August 16th)
* Can execute user defined script after vpn_tunnel is established or broken.

Work on debian based system. Tested on Ubuntu and Raspbian.
Work on Debian and Redhat based system.
Tested on **Ubuntu**, **Raspbian**, **Fedora**.

I will wrap SoftEther_vpn later when I have time. You are welcome to fork this repo and wrap SoftEther_vpn yourself.

Expand Down Expand Up @@ -72,6 +74,16 @@ Except *python 2.7.x*, all other dependencies should be automatically installed

Download: https://github.com/Dragon2fly/vpngate-with-proxy/archive/master.zip
It contains the "vpngate-with-proxy" folder. Extract it into anywhere you want eg: `$HOME`.


**user_script:**

Within this folder, there should be a file `user_script.sh`.
This file allow you to run extra commands to fit your need.
You have to manually edit this file and don't change the file name.
Commands are divided into 2 groups:
- **up**: execute after vpn tunnel is established successfully.
- **down**: execute after vpn tunnel is broken/terminated.

### 2. First run:
If you have configured **system wide proxy** or proxy in firefox, it'd better to **turn** it **off**. After vpn tunnel is established,
Expand Down
34 changes: 34 additions & 0 deletions user_script.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/bin/bash
# This file must be bash script.
# If you need sh/csh/ksh ... then call them within this file.
# This file will be executed with "root" privilege!
# Drop privilege by: su user_name -c "cmd to run"
# DNS should be changed within main program, not here!
# If you manually change your DNS here, you should turn of 'DNS fix' of main program.

# setup any environment variable that you need
set -e
export PATH="$PATH:/usr/sbin:/sbin"

USER=$(whoami)
echo $USER

# Don't modified this block
case "$1" in
up)
# _____ your code here _____
echo "called Up script"
notify-send "$(hostname): LINK IS UP." --icon=network-idle

# _____ end up script ______
;;
down)
# _____ your code here _____
echo "called Down script"
notify-send "$(hostname): LINK IS DOWN !" --icon=dialog-error

# _____ end down script ____
;;
esac

# anything outside "case" block will be executed twice!
144 changes: 80 additions & 64 deletions vpn_indicator.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from Queue import Empty, Queue
from threading import Thread
from subprocess import call, Popen, PIPE
import datetime
import select
import signal, os, sys
import socket, errno
Expand All @@ -28,12 +29,15 @@
satisfied = False


def rep_time():
return str(datetime.datetime.now()).split('.')[0]


class InfoServer:
def __init__(self, port):
self.host = 'localhost'
self.port = port
self.buffer = 2048 # buffer
self.backlog = 1
self.backlog = 0

self.is_listening = False
self.is_connected = False
Expand All @@ -44,28 +48,55 @@ def __init__(self, port):
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.server_address = self.host, self.port

self.last_msg = ''

self.readlist = [self.sock] # use for select

def listen(self):
try:
self.sock.bind(self.server_address)
self.sock.listen(self.backlog)
print 'listening'
print rep_time(), 'listening'

return True
except socket.errno, e:
print e
print rep_time(), e
return False

def accept_it(self):
if not self.is_connected:
self.client, addrr = self.sock.accept()
self.readlist.append(self.client)
self.is_connected = True
print rep_time(), 'Server: Connected with %s:%s' % addrr
return 'Connected'
else:
# reject all other request
client, addrr = self.sock.accept()
client.close()
return 'Another client tried to connect'

def recv_it(self):
data = []
while True:
char = self.client.recv(1)
if not char: # socket close signal
self.is_connected = False
self.readlist.remove(self.client)
print rep_time(), 'main disconnected'
return ''

elif char=='\n':
return ''.join(data)

else:
data.append(char)

def check_io(self, q_info):
"""Receive information about vpn tunnel
:type q_info: Queue
"""
while True:

# try to bind the socket
# try to bind the socket, only run one time
while not self.is_listening:
self.is_listening = self.listen()
time.sleep(2)
Expand All @@ -74,40 +105,26 @@ def check_io(self, q_info):
readable, _, _ = select.select(self.readlist, [], [])
for s in readable:
if s is self.sock:

# sigterm from indicator
if self.is_dead:
print 'Server: Received dead signal'
print rep_time(), 'Server: Received dead signal'
self.sock.close()
return 0
elif not self.is_connected:
self.client, addrr = self.sock.accept()
self.readlist.append(self.client)
self.is_connected = True
print 'Server: Connected with %s:%s' % addrr
q_info.put('connected')

# signal from client
else:
# reject all other request
client, addrr = self.sock.accept()
client.close()
data = self.accept_it()
q_info.put(data)

else: # client sent something
try:

data = self.client.recv(self.buffer)
if data:
print 'main sent: ', data
else:
self.is_connected = False
self.readlist.remove(self.client)
print 'main disconnected'

data = self.recv_it()
q_info.put(data)

except socket.error as e:
print 'Client die unexpectedly'
print rep_time(), 'Client die unexpectedly'
self.is_connected = False
except Exception:
sys.exit()
except Exception as e:
print rep_time(), e

def send(self, msg):
if msg == 'dead':
Expand All @@ -117,7 +134,7 @@ def send(self, msg):

elif self.is_connected:
try:
self.client.sendall(msg)
self.client.sendall(msg + '\n')
return True
except socket.error:
return False
Expand All @@ -129,8 +146,6 @@ class InfoClient:
def __init__(self, port):
self.host = 'localhost'
self.port = port

self.buffer = 2048 # buffer
self.sock = socket.socket()
self.server_address = self.host, port
self.is_connected = False
Expand All @@ -141,38 +156,43 @@ def connect(self):
while not self.is_connected:
try:
self.sock = socket.create_connection(self.server_address)
# print 'socket: connected'
# print rep_time(), 'socket: connected'
self.is_connected = True

# update current status
if self.last_msg:
self.send(self.last_msg)

except socket.error, e:
# print str(e)
# print rep_time(), str(e)
time.sleep(2)

def recv_it(self):
data = []
while True:
char = self.sock.recv(1)
if not char: # socket close signal
self.is_connected = False
return ''
elif char == '\n':
return ''.join(data)
else:
data.append(char)

def check_io(self, q_cmd):
"""Receive information about vpn tunnel
:type q_cmd: Queue
"""
while True:

if self.is_connected:
# check if there is cmd from indicator
readable, _, _ = select.select([self.sock], [], [])
try:

data = self.sock.recv(self.buffer)
data = self.recv_it()
if data:
# print data
q_cmd.put(data)
else:
self.is_connected = False
# print 'server die'

except socket.error as e:
print 'Server die unexpectedly'
print rep_time(), 'Server die unexpectedly'
self.is_connected = False
else:
self.connect()
Expand All @@ -181,7 +201,7 @@ def send(self, msg):
self.last_msg = msg
if self.is_connected:
try:
self.sock.sendall(msg)
self.sock.sendall(msg+'\n')
return True
except socket.error:
return False
Expand Down Expand Up @@ -235,11 +255,11 @@ def blinking(self):

def reload(self, data_in):
if data_in:
print data_in[:12]
print rep_time(), data_in[:12]

self.last_recv = data_in.split(';')
if 'connecting' in data_in:
print 'set blinking'
print rep_time(), 'set blinking'
self.is_connecting = True
else:
self.is_connecting = False
Expand Down Expand Up @@ -328,7 +348,7 @@ def status(self, menu_obj, messages=''):
summary = 'Connected to main program'
body = ''
elif 'successfully' in messages[0]:
print messages[1:]
print rep_time(), messages[1:]
tags = ['Ping:', 'Speed:', 'Up time:', 'Season:', 'Log:', 'Score:', 'Protocol:', 'Portal:']
msg = messages[1:3] + [item for items in zip(tags, messages[3:9]) for item in items]
summary = 'VPN tunnel established'
Expand All @@ -354,31 +374,22 @@ def status(self, menu_obj, messages=''):
self.notifier.show()

def handler(self, signal_num, frame):
print 'Indicator: quit now'
print rep_time(), 'Indicator: quit now'
self.quit('')

def send_cmd(self, menu_obj, arg):
print 'Indicator sent:', arg
print rep_time(), 'Indicator sent:', arg
self.send(arg)

def callback(self):
global t
try:
if not t.isAlive():
self.notifier.update("Error", "Server dead unexpectedly", icon=None)
self.notifier.show()
t = Thread(target=server.check_io, args=(q,))
t.start()

data = self.q_info.get_nowait()
self.reload(data)
except Empty:
pass
except Exception as e:
with open('logs/indicator.log','a+') as log:
log.write(str(e))
self.notifier.update("Error", str(e), icon=None)
self.notifier.show()
self.notifier.update("Error", str(e), icon=None)
self.notifier.show()
return True


Expand All @@ -387,7 +398,7 @@ def callback(self):
another_me = another_me.strip().split('\n')

if len(another_me) > 1:
print 'exist another me', another_me[1:]
print rep_time(), 'exist another me', another_me[1:]
sys.exit()

# queue for interacting between indicator and server
Expand All @@ -398,5 +409,10 @@ def callback(self):
t.start()

indicator = VPNIndicator(q, server.send)
indicator.run()
try:
indicator.run()
except Exception as e:
print rep_time(), 'Indicator:', e
if not server.is_dead:
server.send('dead')
t.join()
Loading

0 comments on commit 6cf0821

Please sign in to comment.