#!/usr/bin/python # -*- coding: utf-8 -*- import cookielib import httplib import os import ustvpaths import socks import socket import ssl try: import stem.process except: pass import time import urllib import urllib2 import xbmc import xbmcaddon from dns.resolver import Resolver addon = xbmcaddon.Addon() IPURL = 'http://icanhazip.com' IPFILE = os.path.join(ustvpaths.DATAPATH,'ip.txt') DNS_REFESH_DELAY = 10 TIMEOUT = 80 RETRY = 10 class MyHTTPConnection(httplib.HTTPConnection): _dnsproxy = [] def connect(self): resolver = Resolver() resolver.nameservers = self._dnsproxy answer = resolver.query(self.host, 'A') self.host = answer.rrset.items[0].address self.sock = socket.create_connection((self.host, self.port)) class MyHTTPHandler(urllib2.HTTPHandler): _dnsproxy = [] def http_open(self, req): MyHTTPConnection._dnsproxy = self._dnsproxy return self.do_open(MyHTTPConnection, req) class SocksiPyConnection(httplib.HTTPConnection): def __init__(self, proxytype, proxyaddr, proxyport = None, rdns = True, username = None, password = None, *args, **kwargs): self.proxyargs = (proxytype, proxyaddr, proxyport, rdns, username, password) httplib.HTTPConnection.__init__(self, *args, **kwargs) def connect(self): self.sock = socks.socksocket() self.sock.setproxy(*self.proxyargs) if isinstance(self.timeout, float): self.sock.settimeout(self.timeout) self.sock.connect((self.host, self.port)) class SocksiPyConnectionS(httplib.HTTPSConnection): """ Missing part for getting https working https://github.com/Anorov/PySocks/blob/master/sockshandler.py """ def __init__(self, proxytype, proxyaddr, proxyport = None, rdns = True, username = None, password = None, *args, **kwargs): self.proxyargs = (proxytype, proxyaddr, proxyport, rdns, username, password) httplib.HTTPSConnection.__init__(self, *args, **kwargs) def connect(self): sock = socks.socksocket() sock.setproxy(*self.proxyargs) if type(self.timeout) in (int, float): sock.settimeout(self.timeout) sock.connect((self.host, self.port)) self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file) class SocksiPyHandler(urllib2.HTTPHandler, urllib2.HTTPSHandler): def __init__(self, *args, **kwargs): self.args = args self.kw = kwargs urllib2.HTTPHandler.__init__(self) def http_open(self, req): def build(host, port = None, strict = None, timeout = 0): conn = SocksiPyConnection(*self.args, host = host, port = port, strict = strict, timeout = timeout, **self.kw) return conn return self.do_open(build, req) def https_open(self, req): def build(host, port = None, strict = None, timeout = 0): conn = SocksiPyConnectionS(*self.args, host = host, port = port, strict = strict, timeout = timeout, **self.kw) return conn return self.do_open(build, req) class TorHandler(): """ With some inspiration from https://github.com/benjkelley/torscraper """ def __init__(self): self.SocksPort = str(addon.getSetting('tor_socks_port')) self.ExitNodes = str(addon.getSetting('tor_exit_node')) self.tor_process = None def start_tor(self): try: tor_cmd = None config = { 'AvoidDiskWrites' : '1', 'ClientOnly' : '1', 'DirReqStatistics' : '0', 'ExcludeExitNodes' : '{be},{pl},{ca},{za},{vn},{uz},{ua},{tw},{tr},{th},{sk},{sg},{se},{sd},{sa},{ru},{ro},{pt},{ph},{pa},{nz},{np},{no},{my},{mx},{md},{lv},{lu},{kr},{jp},{it},{ir},{il},{ie},{id},{hr},{hk},{gr},{gi},{gb},{fi},{es},{ee},{dk},{cz},{cy},{cr},{co},{cn},{cl},{ci},{ch},{by},{br},{bg},{au},{at},{ar},{aq},{ao},{ae},{nl},{de},{fr}', 'ExitNodes' : self.ExitNodes, 'GeoIPExcludeUnknown' : '1', 'NumEntryGuards' : '6', 'SocksListenAddress' : '127.0.0.1', 'SocksPort' : self.SocksPort, 'StrictNodes' : '1' } if 'Tor' not in os.environ['PATH'] and os.name== 'nt': tor_cmd = os.environ['ProgramFiles'] + '\Tor\Tor.exe' if tor_cmd is None: self.tor_process = stem.process.launch_tor_with_config( config = config, init_msg_handler = self.print_bootstrap_lines, take_ownership = True,) else: self.tor_process = stem.process.launch_tor_with_config( config = config, init_msg_handler = self.print_bootstrap_lines, take_ownership = True, tor_cmd = tor_cmd) return True except OSError: return False def kill_tor(self): try: self.tor_process.kill() return True except NameError as e: return False def print_bootstrap_lines(self, line): if 'Bootstrapped ' in line: print line + '\n' def prepare_dns_proxy(cookie_handler): update_url = addon.getSetting('dns_update_url') if update_url: try: t = os.path.getmtime(IPFILE) now = time.time() elapsed = now - t except: elapsed = -1 try: file = open(IPFILE, 'r') oldip = file.read() file.close() except: oldip = '' if elapsed > DNS_REFESH_DELAY or elapsed == -1: myip = getURL(IPURL, connectiontype = 0) if myip != oldip: oldip = myip getURL(update_url, connectiontype = 0) newfile = file = open(IPFILE, 'w') file.write(oldip) file.close() dnsproxy = [] dnsproxy.append(addon.getSetting('dns_proxy')) dnsproxy.append(addon.getSetting('dns_proxy_2')) dnsproxy.append(addon.getSetting('dns_proxy_3')) MyHTTPHandler._dnsproxy = dnsproxy opener = urllib2.build_opener(MyHTTPHandler, cookie_handler) return opener def prepare_us_proxy(cookie_handler): if (addon.getSetting('us_proxy_socks5') == 'true'): if ((addon.getSetting('us_proxy_pass') is not '') and (addon.getSetting('us_proxy_user') is not '')): print 'Using socks5 authenticated proxy: ' + addon.getSetting('us_proxy') + ':' + addon.getSetting('us_proxy_port') socks_handler = SocksiPyHandler(socks.PROXY_TYPE_SOCKS5, addon.getSetting('us_proxy'), int(addon.getSetting('us_proxy_port')), True, addon.getSetting('us_proxy_user'), addon.getSetting('us_proxy_pass')) opener = urllib2.build_opener(socks_handler, cookie_handler) else: print 'Using socks5 proxy: ' + addon.getSetting('us_proxy') + ':' + addon.getSetting('us_proxy_port') socks_handler = SocksiPyHandler(socks.PROXY_TYPE_SOCKS5, addon.getSetting('us_proxy'), int(addon.getSetting('us_proxy_port')), True) opener = urllib2.build_opener(socks_handler, cookie_handler) elif (addon.getSetting('us_proxy_socks5') == 'false'): us_proxy = 'http://' + addon.getSetting('us_proxy') + ':' + addon.getSetting('us_proxy_port') proxy_handler = urllib2.ProxyHandler({'http' : us_proxy}) if ((addon.getSetting('us_proxy_pass') is not '') and (addon.getSetting('us_proxy_user') is not '')): print 'Using authenticated proxy: ' + us_proxy password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm() password_mgr.add_password(None, us_proxy, addon.getSetting('us_proxy_user'), addon.getSetting('us_proxy_pass')) proxy_auth_handler = urllib2.ProxyBasicAuthHandler(password_mgr) opener = urllib2.build_opener(proxy_handler, proxy_auth_handler, cookie_handler) else: print 'Using proxy: ' + us_proxy opener = urllib2.build_opener(proxy_handler, cookie_handler) return opener def prepare_tor_proxy(cookie_handler): if addon.getSetting('tor_use_local') == 'true': tor_proxy = '127.0.0.1' else: tor_proxy = addon.getSetting('tor_proxy') print 'Using tor proxy at ' + tor_proxy + ':' + addon.getSetting('tor_socks_port') + ' with exit node: ' + addon.getSetting('tor_exit_node') socks_handler = SocksiPyHandler(socks.PROXY_TYPE_SOCKS5, tor_proxy, int(addon.getSetting('tor_socks_port')), True) opener = urllib2.build_opener(socks_handler, cookie_handler) return opener def getURL(url, values = None, header = {}, amf = False, savecookie = False, loadcookie = False, connectiontype = addon.getSetting('connectiontype'), cookiefile = 0): success = True retry = 0 while success and retry < RETRY: retry = retry + 1 success = False; old_opener = urllib2._opener try: cj = cookielib.LWPCookieJar(ustvpaths.COOKIE % str(cookiefile)) cookie_handler = urllib2.HTTPCookieProcessor(cj) if int(connectiontype) == 0: urllib2.install_opener(urllib2.build_opener(cookie_handler)) if int(connectiontype) == 1: urllib2.install_opener(prepare_dns_proxy(cookie_handler)) elif int(connectiontype) == 2: urllib2.install_opener(prepare_us_proxy(cookie_handler)) elif int(connectiontype) == 3: handler = TorHandler() if ((addon.getSetting('tor_use_local') == 'true') and addon.getSetting('tor_as_service') == 'false'): if not handler.start_tor(): print 'Error launching Tor. It may already be running.\n' urllib2.install_opener(prepare_tor_proxy(cookie_handler)) print 'connection :: getURL :: url = ' + url if values is None: req = urllib2.Request(bytes(url)) else: if amf == False: data = urllib.urlencode(values) elif amf == True: data = values req = urllib2.Request(bytes(url), data) header.update({'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0'}) if connectiontype == 2: header.update({'X-Forwarded-For' : addon.getSetting('us_proxy')}) elif int(connectiontype) == 1: header.update({'X-Forwarded-For' : addon.getSetting('dns_proxy')}) for key, value in header.iteritems(): req.add_header(key, value) if loadcookie is True: try: cj.load(ignore_discard = True) cj.add_cookie_header(req) except Exception,e: print 'Cookie Loading Error', e pass response = urllib2.urlopen(req, timeout = TIMEOUT) link = response.read() if (savecookie is True): try: cj.save(ignore_discard = True) except Exception, e: print 'Cookie Saving Error', e success = True pass response.close() if ((int(connectiontype) == 3) and (addon.getSetting('tor_use_local') == 'true') and (addon.getSetting('tor_as_service') == 'false')): if not handler.kill_tor(): print 'Error killing Tor process! It may still be running.\n' else: print 'Tor instance killed!\n' except urllib2.HTTPError, error: success = True xbmc.log('HTTP Error reason: ' + str(error), xbmc.LOGINFO) return error.read() except Exception, e: print "URL Error:: ", e else: urllib2.install_opener(old_opener) return link def getRedirect(url, values = None , header = {}, connectiontype = addon.getSetting('connectiontype')): old_opener = urllib2._opener try: cj = cookielib.LWPCookieJar(ustvpaths.COOKIE) cookie_handler = urllib2.HTTPCookieProcessor(cj) if int(connectiontype) == 1: urllib2.install_opener(prepare_dns_proxy(cookie_handler)) elif int(connectiontype) == 2: urllib2.install_opener(prepare_us_proxy(cookie_handler)) elif int(connectiontype) == 3: handler = TorHandler() if ((addon.getSetting('tor_use_local') == 'true') and addon.getSetting('tor_as_service') == 'false'): if not handler.start_tor(): print 'Error launching Tor. It may already be running.\n' urllib2.install_opener(prepare_tor_proxy(cookie_handler)) print 'connection :: getRedirect :: url = ' + url if values is None: req = urllib2.Request(bytes(url)) else: data = urllib.urlencode(values) req = urllib2.Request(bytes(url), data) header.update({'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0'}) if int(connectiontype) == 2: header.update({'X-Forwarded-For' : addon.getSetting('us_proxy')}) elif int(connectiontype) == 1: header.update({'X-Forwarded-For' : addon.getSetting('dns_proxy')}) for key, value in header.iteritems(): req.add_header(key, value) response = urllib2.urlopen(req, timeout = TIMEOUT) finalurl = response.geturl() response.close() if ((int(connectiontype) == 3) and (addon.getSetting('tor_use_local') == 'true') and (addon.getSetting('tor_as_service') == 'false')): if not handler.kill_tor(): print 'Error killing Tor process! It may still be running.\n' else: print 'Tor instance killed!\n' except urllib2.HTTPError, error: print 'HTTP Error reason: ', error return error.read() except Exception, e: print "Error: ", e else: urllib2.install_opener(old_opener) return finalurl