Skip to content

Commit

Permalink
add auto filter dead vpn server out of final list
Browse files Browse the repository at this point in the history
  • Loading branch information
Dragon2fly committed Aug 15, 2016
1 parent e31fa05 commit 5fb7c36
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 35 deletions.
2 changes: 1 addition & 1 deletion vpn_indicator.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

__author__ = 'duc_tin'

from Queue import Queue, Empty
from Queue import Empty
import signal, os
import socket, errno
import time
Expand Down
127 changes: 93 additions & 34 deletions vpnproxy_tui.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,26 @@
__email__ = "[email protected]"

import os
import signal
import base64
import time
import datetime
from copy import deepcopy
from config import *
from Queue import Queue
from subprocess import call, Popen, PIPE
from threading import Thread
from Queue import Queue, Empty
from collections import deque, OrderedDict
from vpn_indicator import *

# Get sudo privilege
euid = os.geteuid()
if euid != 0:
import platform

if 'buntu' in platform.platform() and not Popen(['pgrep', '-f', 'vpn_indicator'], stdout=PIPE).communicate()[0]:
print 'Launch vpn_indicator'
with open('out.txt', 'w+') as f:
Popen(['python', 'vpn_indicator.py'], stdout=PIPE, stderr=PIPE, bufsize=1,)
Popen(['python', 'vpn_indicator.py'], stdout=PIPE, stderr=PIPE, bufsize=1, )

args = ['sudo', sys.executable] + sys.argv + [os.environ]
os.execlpe('sudo', *args)
Expand All @@ -38,6 +38,7 @@
# Define some mirrors of vpngate.net
mirrors = ["http://www.vpngate.net"] # add your mirrors to config.ini file, not here


# TODO: add user manual to this and can be access by h, help. It may never be done, reads the README file instead


Expand Down Expand Up @@ -67,9 +68,12 @@ def write_file(self, use_proxy='no', proxy=None, port=None):
txt_data = txt_data.replace('\r\n;http-proxy [proxy server] [proxy port]\r\n',
'\r\nhttp-proxy %s %s\r\n' % (proxy, port))

extra_option = ['keepalive 5 30\r\n', # prevent connection drop due to inactivity timeout
extra_option = ['keepalive 5 30\r\n', # prevent connection drop due to inactivity timeout
'%s' % ('connect-retry 2\r\n' if self.proto == 'tcp' else ''),
'resolv-retry 2\r\n',
]

txt_data.replace('resolv-retry infinite\r\n', '')
if True:
index = txt_data.find('client\r\n')
txt_data = txt_data[:index] + ''.join(extra_option) + txt_data[index:]
Expand All @@ -83,7 +87,8 @@ def __str__(self):
speed = self.speed / 1000. ** 2
uptime = datetime.timedelta(milliseconds=int(self.uptime))
uptime = re.split(',|\.', str(uptime))[0]
txt = [self.country_short, str(self.ping), '%.2f' % speed, uptime, self.logPolicy, str(self.score), self.proto, self.port]
txt = [self.country_short, str(self.ping), '%.2f' % speed, uptime, self.logPolicy, str(self.score), self.proto,
self.port]
txt = [dta.center(spaces[ind + 1]) for ind, dta in enumerate(txt)]
return ''.join(txt)

Expand Down Expand Up @@ -118,6 +123,8 @@ def __init__(self):
self.kill = False
self.get_limit = 1

self.test_timeout = 2 # probing timeout

self.connected_servers = []
self.messages = OrderedDict([('country', deque([' '], maxlen=1)),
('status', deque([' ', ' '], maxlen=2)),
Expand All @@ -135,8 +142,8 @@ def __init__(self):
else:
get_input(self.cfg, self.args)

self.use_proxy, self.proxy, self.port, self.ip = ['']*4
self.sort_by, self.filters, self.dns_fix, self.dns = ['']*4
self.use_proxy, self.proxy, self.port, self.ip = [''] * 4
self.sort_by, self.filters, self.dns_fix, self.dns = [''] * 4
self.verbose = ''
self.reload()

Expand Down Expand Up @@ -272,6 +279,9 @@ def refresh_data(self, resort_only=''):
port = self.filters['port']
self.vpndict = dict([vpn for vpn in self.vpndict.items() if vpn[1].port in port])

# test alive
self.probe()

if self.sort_by == 'speed':
sort = sorted(self.vpndict.keys(), key=lambda x: self.vpndict[x].speed, reverse=True)
elif self.sort_by == 'ping':
Expand All @@ -287,6 +297,61 @@ def refresh_data(self, resort_only=''):

self.sorted[:] = sort

def probe(self):
""" filter out fetched dead Vpn Servers
"""
target = self.vpndict.keys()

def is_alive(server, queue):
s = socket.socket()
s.settimeout(self.test_timeout)
ip = self.vpndict[server].ip
port = self.vpndict[server].port

if self.use_proxy == 'yes':
s.connect((self.ip, int(self.port))) # connect to proxy server
DATA = 'CONNECT %s:%s HTTP/1.0\r\n\r\n' % (ip, port)
s.send(DATA)
dead = False
try:
response = s.recv(100)
except socket.timeout:
dead = True
finally:
s.shutdown(socket.SHUT_RD)
s.close()

if dead or "200 Connection established" not in response:
queue.put(server)

else:
try:
s.connect((ip, port))
s.shutdown(socket.SHUT_RDWR)
s.close()
except socket.timeout:
queue.put(server)
except Exception as e:
queue.put(server)

my_queue = Queue()
thread_no = 8 # should not be big or you are about to DDoS your proxy server !
i = 0
while i < len(target):
chunk = target[i:i + thread_no]
my_thread = []
for ind, ser in enumerate(chunk):
t = Thread(target=is_alive, args=(ser, my_queue))
t.start()
my_thread.append(t)

for t in my_thread: t.join()
i += thread_no

while not my_queue.empty():
dead_server = my_queue.get()
del self.vpndict[dead_server]

def dns_manager(self, action='backup'):
dns_orig = '/etc/resolv.conf.bak'

Expand Down Expand Up @@ -323,7 +388,7 @@ def vpn_connect(self, chosen):
self.vpn_server = server
self.messages['country'] += [server.country_long.strip('of') + ' ' + server.ip]
self.connected_servers.append(server.ip)
vpn_file = server.write_file(self.use_proxy, self.proxy, self.port)
vpn_file = server.write_file(self.use_proxy, self.ip, self.port)
vpn_file.close()

ovpn = vpn_file.name
Expand All @@ -349,7 +414,7 @@ def vpn_cleanup(self):
tuntap = Popen(['ifconfig', '-s'], stdout=PIPE).communicate()[0]
devices = re.findall('tun\d+', tuntap)
for dev in devices:
call(('ip link delete '+dev).split())
call(('ip link delete ' + dev).split())

def kill_other(self):
"""
Expand Down Expand Up @@ -414,7 +479,6 @@ def __init__(self, vpn_connection):
self.ovpn = vpn_connection
self.get_data = Thread(target=self.ovpn.refresh_data)
self.get_data_status = 'finish'
self.vpn_log = deque(maxlen=20)

self.timer = 0
self.cache_msg = None
Expand Down Expand Up @@ -486,7 +550,7 @@ def periodic_checker(self, loop, user_data=None):
# check if user want to fetch new vpn server list
if 'call' in self.get_data_status and not self.get_data.isAlive():
self.get_vpn_data() # clear the template of server list
self.get_data = Thread(target=self.ovpn.refresh_data, kwargs={'resort_only':self.get_data_status[4:]})
self.get_data = Thread(target=self.ovpn.refresh_data, kwargs={'resort_only': self.get_data_status[4:]})
self.get_data.daemon = True
self.get_data.start()
self.get_data_status = 'wait'
Expand Down Expand Up @@ -520,7 +584,7 @@ def input_handler(self, Edit, key_ls=None):
if key_ls:
if 'q' in key_ls or 'Q' in key_ls:
self.exit(self.loop)
if 'No such server!' == key_ls[:-1] or 'Invalid command!' == key_ls[:-1] or 'refresh' == key_ls[:-1]:
if key_ls[:-1] in ['No such server!', 'Invalid command!', 'refresh']:
self.clear_input = True, key_ls[-1]

# handle for non alphabet key press
Expand Down Expand Up @@ -561,7 +625,8 @@ def input_handler(self, Edit, key_ls=None):
if screen.get_data_status == 'finish':
screen.get_data_status = 'call'
self.input.set_edit_text('')
else: self.input.set_edit_text('Invalid: please wait for last refresh to be finished')
else:
self.input.set_edit_text('Invalid: please wait for last refresh to be finished')
elif 'restore' in text:
self.ovpn.dns_manager('restore')
self.input.set_edit_text('')
Expand All @@ -588,7 +653,8 @@ def input_handler(self, Edit, key_ls=None):
if screen.get_data_status == 'finish':
screen.get_data_status = 'call'
self.input.set_edit_text('')
else: self.input.set_edit_text('Invalid: please wait for last refresh to be finished')
else:
self.input.set_edit_text('Invalid: please wait for last refresh to be finished')
elif key == 'ctrl r':
self.ovpn.dns_manager('restore')
self.input.set_edit_text('')
Expand All @@ -604,6 +670,7 @@ def on_exit_clicked(button):
raise urwid.ExitMainLoop()

def printf(self, txt):
# print a debug msg
self.debug.set_text(str(txt))

def make_GUI(self):
Expand Down Expand Up @@ -667,7 +734,7 @@ def setting(self, key=None):
s_country, s_port = self.ovpn.cfg.filter.values()
dns_fix, dns = self.ovpn.cfg.dns.values()

config_data = [use_proxy, dns_fix, s_country[0:4]+' '+s_port, sort_by]
config_data = [use_proxy, dns_fix, s_country[0:4] + ' ' + s_port, sort_by]
labels = ['Proxy: ', 'DNS fix: ', 'Filter: ', 'Sort by: ']
buttons = ['F2', 'F3', 'F4', 'F5']
popup = [PopUpProxy, PopUpDNS, PopUpCountry, PopUpSortBy]
Expand Down Expand Up @@ -766,13 +833,14 @@ def status(self, msg=None):
ind += 1
return

# create a footer template
message = [urwid.Text(u' ', align='center') for i in range(3)]
debug_mes = [urwid.Text(u' ') for i in range(20)]
return urwid.Pile(message + debug_mes)

def communicator(self, (msg, ovpn)):
if msg:
msgs = 'successfully;'+repr(self.ovpn.vpn_server)
msgs = 'successfully;' + repr(self.ovpn.vpn_server)
self.q2indicator.put(msgs)
else:
self.q2indicator.put('terminate')
Expand All @@ -783,29 +851,19 @@ def logger(self, msg):

logpath = self.ovpn.config_file[:-10] + 'vpn.log'
if msg is None:
# backup last season log
if os.path.exists(logpath):
call(['cp', '-f', logpath, logpath+'.old'])
call(['cp', '-f', logpath, logpath + '.old'])

# make new log file for current season
with open(logpath, 'w+') as log:
log.writelines(['-' * 40 + '\n', time.asctime() + ': Vpngate with proxy is started\n'])

else:
with open(logpath, 'a+') as log:
if msg['debug'] != self.vpn_log and ' Pinging proxy... ' not in msg['debug']:
ind = 0
m = msg['debug'][ind]
if self.vpn_log:
while m != self.vpn_log[0]:
ind += 1
m = msg['debug'][ind]
while ind > 0:
ind -= 1
m = msg['debug'][ind]
self.vpn_log.appendleft(m)
log.write(m + '\n')
else:
for m in list(msg['debug'])[::-1]:
self.vpn_log.appendleft(m)
log.write(m + '\n')
if ' Pinging proxy... ' not in msg['debug']:
m = msg['debug'].pop()
log.write(m + '\n')

def run(self):
self.loop.run()
Expand All @@ -817,10 +875,11 @@ def exit(self, loop, data=None):
else:
self.ovpn.kill = True


# ------------------------- Main -----------------------------------
vpn_connect = Connection() # initiate network parameter

# ------------------- check_dependencies: ---------------------------
# check_dependencies:
required = {'openvpn': 0, 'python-pip': 0, 'requests': 0, 'urwid': 0}
for module in ['pip', 'requests', 'urwid']:
try:
Expand Down

0 comments on commit 5fb7c36

Please sign in to comment.