PageRenderTime 83ms CodeModel.GetById 39ms RepoModel.GetById 1ms app.codeStats 1ms

/simpleproxy.py

https://github.com/greatagent3/esr
Python | 1799 lines | 1750 code | 42 blank | 7 comment | 64 complexity | 33bea6f419e09bed55ae146a4e7d03d1 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. #!/usr/bin/env python
  2. # coding:utf-8
  3. # Based on GoAgent 3.1.16 by Phus Lu <phus.lu@gmail.com>
  4. # Author: Wang Wei Qiang <wwqgtxx@gmail.com>
  5. __version__ = '3.0.0'
  6. import sys
  7. import os
  8. import glob
  9. reload(sys).setdefaultencoding('UTF-8')
  10. sys.dont_write_bytecode = True
  11. sys.path += glob.glob('%s/*.egg' % os.path.dirname(os.path.abspath(__file__)))
  12. sys.path += glob.glob('%s/lib/*.egg' % os.path.dirname(os.path.abspath(__file__)))
  13. try:
  14. import gevent
  15. import gevent.socket
  16. import gevent.server
  17. import gevent.queue
  18. import gevent.monkey
  19. gevent.monkey.patch_all(subprocess=True)
  20. except ImportError:
  21. gevent = None
  22. except TypeError:
  23. gevent.monkey.patch_all()
  24. sys.stderr.write('\033[31m Warning: Please update gevent to the latest 1.0 version!\033[0m\n')
  25. import errno
  26. import time
  27. import struct
  28. import collections
  29. import binascii
  30. import zlib
  31. import itertools
  32. import re
  33. import io
  34. import fnmatch
  35. import traceback
  36. import random
  37. import base64
  38. import string
  39. import hashlib
  40. import threading
  41. import thread
  42. import socket
  43. import ssl
  44. import select
  45. import Queue
  46. import SocketServer
  47. import ConfigParser
  48. import BaseHTTPServer
  49. import httplib
  50. import urllib
  51. import urllib2
  52. import urlparse
  53. try:
  54. import dnslib
  55. except ImportError:
  56. dnslib = None
  57. try:
  58. import OpenSSL
  59. except ImportError:
  60. OpenSSL = None
  61. try:
  62. import pygeoip
  63. except ImportError:
  64. pygeoip = None
  65. HAS_PYPY = hasattr(sys, 'pypy_version_info')
  66. NetWorkIOError = (socket.error, ssl.SSLError, OSError) if not OpenSSL else (socket.error, ssl.SSLError, OpenSSL.SSL.Error, OSError)
  67. class Logging(type(sys)):
  68. CRITICAL = 50
  69. FATAL = CRITICAL
  70. ERROR = 40
  71. WARNING = 30
  72. WARN = WARNING
  73. INFO = 20
  74. DEBUG = 10
  75. NOTSET = 0
  76. def __init__(self, *args, **kwargs):
  77. self.level = self.__class__.INFO
  78. self.__set_error_color = lambda: None
  79. self.__set_warning_color = lambda: None
  80. self.__set_debug_color = lambda: None
  81. self.__reset_color = lambda: None
  82. if hasattr(sys.stderr, 'isatty') and sys.stderr.isatty():
  83. if os.name == 'nt':
  84. import ctypes
  85. SetConsoleTextAttribute = ctypes.windll.kernel32.SetConsoleTextAttribute
  86. GetStdHandle = ctypes.windll.kernel32.GetStdHandle
  87. self.__set_error_color = lambda: SetConsoleTextAttribute(GetStdHandle(-11), 0x04)
  88. self.__set_warning_color = lambda: SetConsoleTextAttribute(GetStdHandle(-11), 0x06)
  89. self.__set_debug_color = lambda: SetConsoleTextAttribute(GetStdHandle(-11), 0x002)
  90. self.__reset_color = lambda: SetConsoleTextAttribute(GetStdHandle(-11), 0x07)
  91. elif os.name == 'posix':
  92. self.__set_error_color = lambda: sys.stderr.write('\033[31m')
  93. self.__set_warning_color = lambda: sys.stderr.write('\033[33m')
  94. self.__set_debug_color = lambda: sys.stderr.write('\033[32m')
  95. self.__reset_color = lambda: sys.stderr.write('\033[0m')
  96. @classmethod
  97. def getLogger(cls, *args, **kwargs):
  98. return cls(*args, **kwargs)
  99. def basicConfig(self, *args, **kwargs):
  100. self.level = int(kwargs.get('level', self.__class__.INFO))
  101. if self.level > self.__class__.DEBUG:
  102. self.debug = self.dummy
  103. def log(self, level, fmt, *args, **kwargs):
  104. sys.stderr.write('%s - [%s] %s\n' % (level, time.ctime()[4:-5], fmt % args))
  105. def dummy(self, *args, **kwargs):
  106. pass
  107. def debug(self, fmt, *args, **kwargs):
  108. pass
  109. def info(self, fmt, *args, **kwargs):
  110. pass
  111. def warning(self, fmt, *args, **kwargs):
  112. self.__set_warning_color()
  113. self.log('WARNING', fmt, *args, **kwargs)
  114. self.__reset_color()
  115. def warn(self, fmt, *args, **kwargs):
  116. self.warning(fmt, *args, **kwargs)
  117. def error(self, fmt, *args, **kwargs):
  118. self.__set_error_color()
  119. self.log('ERROR', fmt, *args, **kwargs)
  120. self.__reset_color()
  121. def exception(self, fmt, *args, **kwargs):
  122. self.error(fmt, *args, **kwargs)
  123. sys.stderr.write(traceback.format_exc() + '\n')
  124. def critical(self, fmt, *args, **kwargs):
  125. self.__set_error_color()
  126. self.log('CRITICAL', fmt, *args, **kwargs)
  127. self.__reset_color()
  128. logging = sys.modules['logging'] = Logging('logging')
  129. class LRUCache(object):
  130. """http://pypi.python.org/pypi/lru/"""
  131. def __init__(self, max_items=100):
  132. self.cache = {}
  133. self.key_order = []
  134. self.max_items = max_items
  135. def __setitem__(self, key, value):
  136. self.cache[key] = value
  137. self._mark(key)
  138. def __getitem__(self, key):
  139. value = self.cache[key]
  140. self._mark(key)
  141. return value
  142. def __contains__(self, key):
  143. return key in self.cache
  144. def _mark(self, key):
  145. if key in self.key_order:
  146. self.key_order.remove(key)
  147. self.key_order.insert(0, key)
  148. if len(self.key_order) > self.max_items:
  149. index = self.max_items // 2
  150. delitem = self.cache.__delitem__
  151. key_order = self.key_order
  152. any(delitem(key_order[x]) for x in xrange(index, len(key_order)))
  153. self.key_order = self.key_order[:index]
  154. def clear(self):
  155. self.cache = {}
  156. self.key_order = []
  157. class CertUtil(object):
  158. """CertUtil module, based on mitmproxy"""
  159. ca_vendor = 'GoAgent'
  160. ca_certdir = 'certs'
  161. ca_lock = threading.Lock()
  162. @staticmethod
  163. def create_ca():
  164. key = OpenSSL.crypto.PKey()
  165. key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048)
  166. ca = OpenSSL.crypto.X509()
  167. ca.set_serial_number(0)
  168. ca.set_version(2)
  169. subj = ca.get_subject()
  170. subj.countryName = 'CN'
  171. subj.stateOrProvinceName = 'Internet'
  172. subj.localityName = 'Cernet'
  173. subj.organizationName = CertUtil.ca_vendor
  174. subj.organizationalUnitName = '%s Root' % CertUtil.ca_vendor
  175. subj.commonName = '%s CA' % CertUtil.ca_vendor
  176. ca.gmtime_adj_notBefore(0)
  177. ca.gmtime_adj_notAfter(24 * 60 * 60 * 3652)
  178. ca.set_issuer(ca.get_subject())
  179. ca.set_pubkey(key)
  180. ca.add_extensions([
  181. OpenSSL.crypto.X509Extension(b'basicConstraints', True, b'CA:TRUE'),
  182. OpenSSL.crypto.X509Extension(b'nsCertType', True, b'sslCA'),
  183. OpenSSL.crypto.X509Extension(b'extendedKeyUsage', True, b'serverAuth,clientAuth,emailProtection,timeStamping,msCodeInd,msCodeCom,msCTLSign,msSGC,msEFS,nsSGC'),
  184. OpenSSL.crypto.X509Extension(b'keyUsage', False, b'keyCertSign, cRLSign'),
  185. OpenSSL.crypto.X509Extension(b'subjectKeyIdentifier', False, b'hash', subject=ca), ])
  186. ca.sign(key, 'sha1')
  187. return key, ca
  188. @staticmethod
  189. def dump_ca():
  190. key, ca = CertUtil.create_ca()
  191. with open(CertUtil.ca_keyfile, 'wb') as fp:
  192. fp.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, ca))
  193. fp.write(OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, key))
  194. @staticmethod
  195. def _get_cert(commonname, sans=()):
  196. content = """
  197. -----BEGIN CERTIFICATE-----
  198. MIIDUjCCAjoCAQAwDQYJKoZIhvcNAQEFBQAwbzEVMBMGA1UECxMMR29BZ2VudCBS
  199. b290MRAwDgYDVQQKEwdHb0FnZW50MRMwEQYDVQQDEwpHb0FnZW50IENBMREwDwYD
  200. VQQIEwhJbnRlcm5ldDELMAkGA1UEBhMCQ04xDzANBgNVBAcTBkNlcm5ldDAeFw0x
  201. MTA0MjAxNzM3MzVaFw0zMTA0MjAxNzM3MzVaMG8xFTATBgNVBAsTDEdvQWdlbnQg
  202. Um9vdDEQMA4GA1UEChMHR29BZ2VudDETMBEGA1UEAxMKR29BZ2VudCBDQTERMA8G
  203. A1UECBMISW50ZXJuZXQxCzAJBgNVBAYTAkNOMQ8wDQYDVQQHEwZDZXJuZXQwggEi
  204. MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0jV3yx3yGAHlQqzm4fbVascvT
  205. nyCdtParWBnQn5A3U9pJjI47SCo8j7FfeoYSL0mHbJ0mjafTnw+/ewb09AQIkdEl
  206. n6smojl7NOKs1Yhh0yldB6kQWiBPr/XKMBskmvcyjJEqkU6hwtibASaAZt+q5clT
  207. BJ2XRaeAaMDeDbYDchFa7MTNhoQMdQFu1UhqkJxtuVMBEs1/qPbx5O9pqy1RgAeK
  208. WvxyCzVRi2hHaTns+weZBJ6N71afyvr1etGqqtWVpjpobk1ZFBYk4xpznCbm4iqP
  209. Ar9nqdGDw1IJIdX0DyMJIJrpwOf94pAK9v6zG0jnsbMqromL18kEMXZgYSMlAgMB
  210. AAEwDQYJKoZIhvcNAQEFBQADggEBAASiRZFCcgQ8VsncB8wKG+bmN9UZhXLJYRGp
  211. m3KIUy/zG6mMWG/3TgkPn8ivNAkrk+1ul5SrRvot/Q7XWpb0/yKX0faX/512JF2G
  212. 220gopqo4amj+g7SBKxzW8VhLQF6dm99eUd27JbAzi5VKXR0dMFECk2rFlA5gAR5
  213. zzFijaXHuObMtd2S292wji79JWocA0z6WVM5Qokw4hRTsXWfXL0BJTL3i/xRrEzW
  214. sdecYFpNhaEKldjegazoqAqiAMJj7PDU1AqdprNsq+3/tAmCvn0URkas4QhkvtqS
  215. FO6OGm/PZe5GbkBpAKdfLYFfEMO17SAGHHqAsIKAFfuHYONRGSM=
  216. -----END CERTIFICATE-----
  217. -----BEGIN RSA PRIVATE KEY-----
  218. MIIEowIBAAKCAQEAtI1d8sd8hgB5UKs5uH21WrHL058gnbT2q1gZ0J+QN1PaSYyO
  219. O0gqPI+xX3qGEi9Jh2ydJo2n058Pv3sG9PQECJHRJZ+rJqI5ezTirNWIYdMpXQep
  220. EFogT6/1yjAbJJr3MoyRKpFOocLYmwEmgGbfquXJUwSdl0WngGjA3g22A3IRWuzE
  221. zYaEDHUBbtVIapCcbblTARLNf6j28eTvaastUYAHilr8cgs1UYtoR2k57PsHmQSe
  222. je9Wn8r69XrRqqrVlaY6aG5NWRQWJOMac5wm5uIqjwK/Z6nRg8NSCSHV9A8jCSCa
  223. 6cDn/eKQCvb+sxtI57GzKq6Ji9fJBDF2YGEjJQIDAQABAoIBACB3n2JN/xV1tlsM
  224. P1fuuxLxD+8hGVNivEy5jgLW/q8EVCePr+/3HSlAyauas8tHV5iTrnrFVF2Yp9NO
  225. A0U/MA5+cjaqzLMozt9Z9j0QNPMqbrC89Ojs3AyYXsGZ/veJKlSbtGsMMDCkgiD1
  226. hv/l/+iSY66bEN+n9eQAclY77vQVXLSoCMReVfbdUxU9Q1MywODGf5Kng84gTyT/
  227. zd+xEfFHz8zbCDyw3Hd3hGJ2FxN+yFz1uI29ORb3/R7N9dZgsWf2fsfiRVPGuhAH
  228. RNlDockImB+BKeidx14sMim5p7s8heVYkBVW3SIOEReqz59b8x4QVhhZrzYWSHNq
  229. Gi0pLiECgYEA26v6b+rsxT//PznJSEhLyrg1Jo6XeWmFlwZY0KoipH6sxX/YPrDZ
  230. bOPN8KvAHtRltRLFs3L2iRaO2jltjxHGVF4FSYrf5KSExuj6/ABHxWM0YtezfDwR
  231. hU1ORg5QwVegMoOgsphS8ts2xn6T6wIwpBgtFPY84A52IBVn5CHuQtkCgYEA0mk5
  232. EpnZfmMT5ldcZ7JlZrxfWKvDHIcuA0neIBsd4oIcEfRhDC3TolH6pB4z4SCqyYw3
  233. t5HMiTx8yz074mycTcOcXO1Cs49kMZwbzKziRXpUdCW4EIo0DG+6LqwetPgYzozg
  234. FeTiGQBHqjrzjBLZ3RfozICbo7dvYHkVLK92my0CgYBWNBjlDnW3ujN6Jj0cxnIn
  235. rT3+UXqTxJsN9wmnaPyLPMKkBlVf1JqeJo9MYLnV31fCRQmcMAMbLOUGMf8SY9FG
  236. jlbY00ylNwJ75DWJ6ro/dXy7RRZELHZbr0iGKVv7Y12UNR88tpXmg6vtHQMC+CsK
  237. Wgpm7XJaIpKsaHoKhl4vkQKBgBBBTsZwGkxYTSZDY4EjWBAax2brRhSDIPviDgX+
  238. 8k0YbiC493Jga/QjTzC0oJ9ozajqazeETP/hK2bsIR858s1TKlZHghqrHjty6vbh
  239. +E0TyUh7zX+BncnEK+cFJw4mCIyUd49ZcloqGl89VKlin3AkM7jwypVYS4Nxd0BP
  240. geM1AoGBALOWNmYm9d4gRhUv14oJRiA+e+4evswiWvVdnS6UJ4tst0NlEKWahtpR
  241. kdAjav8WV1n6IbkJC2L743Ozjb63z5w6p5O7OtTyYUWbLt1hvNkHlkNP8AjRQP8E
  242. +N2jjrMAdbEwahPNAX9QlzHpF62AfEGQ3oODUm06TGTq+yAPSyYm
  243. -----END RSA PRIVATE KEY-----
  244. """
  245. key = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, content)
  246. ca = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, content)
  247. pkey = OpenSSL.crypto.PKey()
  248. pkey.generate_key(OpenSSL.crypto.TYPE_RSA, 2048)
  249. req = OpenSSL.crypto.X509Req()
  250. subj = req.get_subject()
  251. subj.countryName = 'CN'
  252. subj.stateOrProvinceName = 'Internet'
  253. subj.localityName = 'Cernet'
  254. subj.organizationalUnitName = '%s Branch' % CertUtil.ca_vendor
  255. if commonname[0] == '.':
  256. subj.commonName = '*' + commonname
  257. subj.organizationName = '*' + commonname
  258. sans = ['*'+commonname] + [x for x in sans if x != '*'+commonname]
  259. else:
  260. subj.commonName = commonname
  261. subj.organizationName = commonname
  262. sans = [commonname] + [x for x in sans if x != commonname]
  263. #req.add_extensions([OpenSSL.crypto.X509Extension(b'subjectAltName', True, ', '.join('DNS: %s' % x for x in sans)).encode()])
  264. req.set_pubkey(pkey)
  265. req.sign(pkey, 'sha1')
  266. cert = OpenSSL.crypto.X509()
  267. cert.set_version(2)
  268. try:
  269. cert.set_serial_number(int(hashlib.md5(commonname.encode('utf-8')).hexdigest(), 16))
  270. except OpenSSL.SSL.Error:
  271. cert.set_serial_number(int(time.time()*1000))
  272. cert.gmtime_adj_notBefore(0)
  273. cert.gmtime_adj_notAfter(60 * 60 * 24 * 3652)
  274. cert.set_issuer(ca.get_subject())
  275. cert.set_subject(req.get_subject())
  276. cert.set_pubkey(req.get_pubkey())
  277. if commonname[0] == '.':
  278. sans = ['*'+commonname] + [s for s in sans if s != '*'+commonname]
  279. else:
  280. sans = [commonname] + [s for s in sans if s != commonname]
  281. #cert.add_extensions([OpenSSL.crypto.X509Extension(b'subjectAltName', True, ', '.join('DNS: %s' % x for x in sans))])
  282. cert.sign(key, 'sha1')
  283. certfile = os.path.join(CertUtil.ca_certdir, commonname + '.crt')
  284. with open(certfile, 'wb') as fp:
  285. fp.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert))
  286. fp.write(OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, pkey))
  287. return certfile
  288. @staticmethod
  289. def get_cert(commonname, sans=()):
  290. if commonname.count('.') >= 2 and len(commonname.split('.')[-2]) > 4:
  291. commonname = '.'+commonname.partition('.')[-1]
  292. certfile = os.path.join(CertUtil.ca_certdir, commonname + '.crt')
  293. if os.path.exists(certfile):
  294. return certfile
  295. elif OpenSSL is None:
  296. return CertUtil.ca_keyfile
  297. else:
  298. with CertUtil.ca_lock:
  299. if os.path.exists(certfile):
  300. return certfile
  301. return CertUtil._get_cert(commonname, sans)
  302. @staticmethod
  303. def import_ca(certfile):
  304. commonname = os.path.splitext(os.path.basename(certfile))[0]
  305. if OpenSSL:
  306. try:
  307. with open(certfile, 'rb') as fp:
  308. x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, fp.read())
  309. commonname = next(v.decode() for k, v in x509.get_subject().get_components() if k == b'O')
  310. except Exception as e:
  311. logging.error('load_certificate(certfile=%r) failed:%s', certfile, e)
  312. if sys.platform.startswith('win'):
  313. import ctypes
  314. with open(certfile, 'rb') as fp:
  315. certdata = fp.read()
  316. if certdata.startswith(b'-----'):
  317. begin = b'-----BEGIN CERTIFICATE-----'
  318. end = b'-----END CERTIFICATE-----'
  319. certdata = base64.b64decode(b''.join(certdata[certdata.find(begin)+len(begin):certdata.find(end)].strip().splitlines()))
  320. crypt32 = ctypes.WinDLL(b'crypt32.dll'.decode())
  321. store_handle = crypt32.CertOpenStore(10, 0, 0, 0x4000 | 0x20000, b'ROOT'.decode())
  322. if not store_handle:
  323. return -1
  324. if crypt32.CertFindCertificateInStore(store_handle, 0x1, 0, 0x80007, CertUtil.ca_vendor.decode(), None):
  325. return 0
  326. ret = crypt32.CertAddEncodedCertificateToStore(store_handle, 0x1, certdata, len(certdata), 4, None)
  327. crypt32.CertCloseStore(store_handle, 0)
  328. del crypt32
  329. return 0 if ret else -1
  330. elif sys.platform == 'darwin':
  331. return os.system(('security find-certificate -a -c "%s" | grep "%s" >/dev/null || security add-trusted-cert -d -r trustRoot -k "/Library/Keychains/System.keychain" "%s"' % (commonname, commonname, certfile.decode('utf-8'))).encode('utf-8'))
  332. elif sys.platform.startswith('linux'):
  333. import platform
  334. platform_distname = platform.dist()[0]
  335. if platform_distname == 'Ubuntu':
  336. pemfile = "/etc/ssl/certs/%s.pem" % commonname
  337. new_certfile = "/usr/local/share/ca-certificates/%s.crt" % commonname
  338. if not os.path.exists(pemfile):
  339. return os.system('cp "%s" "%s" && update-ca-certificates' % (certfile, new_certfile))
  340. elif any(os.path.isfile('%s/certutil' % x) for x in os.environ['PATH'].split(os.pathsep)):
  341. return os.system('certutil -L -d sql:$HOME/.pki/nssdb | grep "%s" || certutil -d sql:$HOME/.pki/nssdb -A -t "C,," -n "%s" -i "%s"' % (commonname, commonname, certfile))
  342. else:
  343. logging.warning('please install *libnss3-tools* package to import GoAgent root ca')
  344. return 0
  345. @staticmethod
  346. def check_ca():
  347. #Check CA exists
  348. capath = os.path.join(os.path.dirname(os.path.abspath(__file__)), CertUtil.ca_keyfile)
  349. certdir = os.path.join(os.path.dirname(os.path.abspath(__file__)), CertUtil.ca_certdir)
  350. if not os.path.exists(capath):
  351. if not OpenSSL:
  352. logging.critical('CA.key is not exist and OpenSSL is disabled, ABORT!')
  353. sys.exit(-1)
  354. if os.path.exists(certdir):
  355. if os.path.isdir(certdir):
  356. any(os.remove(x) for x in glob.glob(certdir+'/*.crt')+glob.glob(certdir+'/.*.crt'))
  357. else:
  358. os.remove(certdir)
  359. os.mkdir(certdir)
  360. CertUtil.dump_ca()
  361. if glob.glob('%s/*.key' % CertUtil.ca_certdir):
  362. for filename in glob.glob('%s/*.key' % CertUtil.ca_certdir):
  363. try:
  364. os.remove(filename)
  365. os.remove(os.path.splitext(filename)[0]+'.crt')
  366. except EnvironmentError:
  367. pass
  368. #Check CA imported
  369. if CertUtil.import_ca(capath) != 0:
  370. logging.warning('install root certificate failed, Please run as administrator/root/sudo')
  371. #Check Certs Dir
  372. if not os.path.exists(certdir):
  373. os.makedirs(certdir)
  374. class SSLConnection(object):
  375. """OpenSSL Connection Wapper"""
  376. def __init__(self, context, sock):
  377. self._context = context
  378. self._sock = sock
  379. self._connection = OpenSSL.SSL.Connection(context, sock)
  380. self._makefile_refs = 0
  381. def __getattr__(self, attr):
  382. if attr not in ('_context', '_sock', '_connection', '_makefile_refs'):
  383. return getattr(self._connection, attr)
  384. def __wait_sock_io(self, sock, io_func, *args, **kwargs):
  385. timeout = self._sock.gettimeout() or 0.1
  386. fd = self._sock.fileno()
  387. while True:
  388. try:
  389. return io_func(*args, **kwargs)
  390. except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantX509LookupError):
  391. sys.exc_clear()
  392. _, _, errors = select.select([fd], [], [fd], timeout)
  393. if errors:
  394. break
  395. except OpenSSL.SSL.WantWriteError:
  396. sys.exc_clear()
  397. _, _, errors = select.select([], [fd], [fd], timeout)
  398. if errors:
  399. break
  400. def accept(self):
  401. sock, addr = self._sock.accept()
  402. client = OpenSSL.SSL.Connection(sock._context, sock)
  403. return client, addr
  404. def do_handshake(self):
  405. return self.__wait_sock_io(self._sock, self._connection.do_handshake)
  406. def connect(self, *args, **kwargs):
  407. return self.__wait_sock_io(self._sock, self._connection.connect, *args, **kwargs)
  408. def send(self, data, flags=0):
  409. try:
  410. return self.__wait_sock_io(self._sock, self._connection.send, data, flags)
  411. except OpenSSL.SSL.SysCallError as e:
  412. if e[0] == -1 and not data:
  413. # errors when writing empty strings are expected and can be ignored
  414. return 0
  415. raise
  416. def recv(self, bufsiz, flags=0):
  417. pending = self._connection.pending()
  418. if pending:
  419. return self._connection.recv(min(pending, bufsiz))
  420. try:
  421. return self.__wait_sock_io(self._sock, self._connection.recv, bufsiz, flags)
  422. except OpenSSL.SSL.ZeroReturnError:
  423. return ''
  424. def read(self, bufsiz, flags=0):
  425. return self.recv(bufsiz, flags)
  426. def write(self, buf, flags=0):
  427. return self.sendall(buf, flags)
  428. def close(self):
  429. if self._makefile_refs < 1:
  430. self._connection = None
  431. if self._sock:
  432. socket.socket.close(self._sock)
  433. else:
  434. self._makefile_refs -= 1
  435. def makefile(self, mode='r', bufsize=-1):
  436. self._makefile_refs += 1
  437. return socket._fileobject(self, mode, bufsize, close=True)
  438. def parse_hostport(host, default_port=80):
  439. m = re.match(r'(.+)[#](\d+)$', host)
  440. if m:
  441. return m.group(1).strip('[]'), int(m.group(2))
  442. else:
  443. return host.strip('[]'), default_port
  444. def dnslib_resolve_over_udp(query, dnsservers, timeout, **kwargs):
  445. """
  446. http://gfwrev.blogspot.com/2009/11/gfwdns.html
  447. http://zh.wikipedia.org/wiki/%E5%9F%9F%E5%90%8D%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%BC%93%E5%AD%98%E6%B1%A1%E6%9F%93
  448. http://support.microsoft.com/kb/241352
  449. """
  450. if not isinstance(query, (basestring, dnslib.DNSRecord)):
  451. raise TypeError('query argument requires string/DNSRecord')
  452. blacklist = kwargs.get('blacklist', ())
  453. turstservers = kwargs.get('turstservers', ())
  454. dns_v4_servers = [x for x in dnsservers if ':' not in x]
  455. dns_v6_servers = [x for x in dnsservers if ':' in x]
  456. sock_v4 = sock_v6 = None
  457. socks = []
  458. if dns_v4_servers:
  459. sock_v4 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  460. socks.append(sock_v4)
  461. if dns_v6_servers:
  462. sock_v6 = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
  463. socks.append(sock_v6)
  464. timeout_at = time.time() + timeout
  465. try:
  466. for _ in xrange(4):
  467. try:
  468. for dnsserver in dns_v4_servers:
  469. if isinstance(query, basestring):
  470. query = dnslib.DNSRecord(q=dnslib.DNSQuestion(query))
  471. query_data = query.pack()
  472. sock_v4.sendto(query_data, parse_hostport(dnsserver, 53))
  473. for dnsserver in dns_v6_servers:
  474. if isinstance(query, basestring):
  475. query = dnslib.DNSRecord(q=dnslib.DNSQuestion(query, qtype=dnslib.QTYPE.AAAA))
  476. query_data = query.pack()
  477. sock_v6.sendto(query_data, parse_hostport(dnsserver, 53))
  478. while time.time() < timeout_at:
  479. ins, _, _ = select.select(socks, [], [], 0.1)
  480. for sock in ins:
  481. reply_data, reply_address = sock.recvfrom(512)
  482. reply_server = reply_address[0]
  483. record = dnslib.DNSRecord.parse(reply_data)
  484. iplist = [str(x.rdata) for x in record.rr if x.rtype in (1, 28, 255)]
  485. if any(x in blacklist for x in iplist):
  486. logging.debug('query=%r dnsservers=%r record bad iplist=%r', query, dnsservers, iplist)
  487. elif record.header.rcode and not iplist and reply_server in turstservers:
  488. logging.info('query=%r trust reply_server=%r record rcode=%s', query, reply_server, record.header.rcode)
  489. return record
  490. elif iplist:
  491. logging.debug('query=%r reply_server=%r record iplist=%s', query, reply_server, iplist)
  492. return record
  493. else:
  494. logging.debug('query=%r reply_server=%r record null iplist=%s', query, reply_server, iplist)
  495. continue
  496. except socket.error as e:
  497. logging.warning('handle dns query=%s socket: %r', query, e)
  498. raise socket.gaierror(11004, 'getaddrinfo %r from %r failed' % (query, dnsservers))
  499. finally:
  500. for sock in socks:
  501. sock.close()
  502. def dnslib_resolve_over_tcp(query, dnsservers, timeout, **kwargs):
  503. """dns query over tcp"""
  504. if not isinstance(query, (basestring, dnslib.DNSRecord)):
  505. raise TypeError('query argument requires string/DNSRecord')
  506. blacklist = kwargs.get('blacklist', ())
  507. def do_resolve(query, dnsserver, timeout, queobj):
  508. if isinstance(query, basestring):
  509. qtype = dnslib.QTYPE.AAAA if ':' in dnsserver else dnslib.QTYPE.A
  510. query = dnslib.DNSRecord(q=dnslib.DNSQuestion(query, qtype=qtype))
  511. query_data = query.pack()
  512. sock_family = socket.AF_INET6 if ':' in dnsserver else socket.AF_INET
  513. sock = socket.socket(sock_family)
  514. rfile = None
  515. try:
  516. sock.settimeout(timeout or None)
  517. sock.connect(parse_hostport(dnsserver, 53))
  518. sock.send(struct.pack('>h', len(query_data)) + query_data)
  519. rfile = sock.makefile('r', 1024)
  520. reply_data_length = rfile.read(2)
  521. if len(reply_data_length) < 2:
  522. raise socket.gaierror(11004, 'getaddrinfo %r from %r failed' % (query, dnsserver))
  523. reply_data = rfile.read(struct.unpack('>h', reply_data_length)[0])
  524. record = dnslib.DNSRecord.parse(reply_data)
  525. iplist = [str(x.rdata) for x in record.rr if x.rtype in (1, 28, 255)]
  526. if any(x in blacklist for x in iplist):
  527. logging.debug('query=%r dnsserver=%r record bad iplist=%r', query, dnsserver, iplist)
  528. raise socket.gaierror(11004, 'getaddrinfo %r from %r failed' % (query, dnsserver))
  529. else:
  530. logging.debug('query=%r dnsserver=%r record iplist=%s', query, dnsserver, iplist)
  531. queobj.put(record)
  532. except socket.error as e:
  533. logging.debug('query=%r dnsserver=%r failed %r', query, dnsserver, e)
  534. queobj.put(e)
  535. finally:
  536. if rfile:
  537. rfile.close()
  538. sock.close()
  539. queobj = Queue.Queue()
  540. for dnsserver in dnsservers:
  541. thread.start_new_thread(do_resolve, (query, dnsserver, timeout, queobj))
  542. for i in range(len(dnsservers)):
  543. try:
  544. result = queobj.get(timeout)
  545. except Queue.Empty:
  546. raise socket.gaierror(11004, 'getaddrinfo %r from %r failed' % (query, dnsservers))
  547. if result and not isinstance(result, Exception):
  548. return result
  549. elif i == len(dnsservers) - 1:
  550. logging.warning('dnslib_resolve_over_tcp %r with %s return %r', query, dnsservers, result)
  551. raise socket.gaierror(11004, 'getaddrinfo %r from %r failed' % (query, dnsservers))
  552. def dnslib_record2iplist(record):
  553. """convert dnslib.DNSRecord to iplist"""
  554. assert isinstance(record, dnslib.DNSRecord)
  555. iplist = [x for x in (str(r.rdata) for r in record.rr) if re.match(r'^\d+\.\d+\.\d+\.\d+$', x) or ':' in x]
  556. return iplist
  557. def get_dnsserver_list():
  558. if os.name == 'nt':
  559. import ctypes, ctypes.wintypes, struct, socket
  560. DNS_CONFIG_DNS_SERVER_LIST = 6
  561. buf = ctypes.create_string_buffer(2048)
  562. ctypes.windll.dnsapi.DnsQueryConfig(DNS_CONFIG_DNS_SERVER_LIST, 0, None, None, ctypes.byref(buf), ctypes.byref(ctypes.wintypes.DWORD(len(buf))))
  563. ipcount = struct.unpack('I', buf[0:4])[0]
  564. iplist = [socket.inet_ntoa(buf[i:i+4]) for i in xrange(4, ipcount*4+4, 4)]
  565. return iplist
  566. elif os.path.isfile('/etc/resolv.conf'):
  567. with open('/etc/resolv.conf', 'rb') as fp:
  568. return re.findall(r'(?m)^nameserver\s+(\S+)', fp.read())
  569. else:
  570. logging.warning("get_dnsserver_list failed: unsupport platform '%s-%s'", sys.platform, os.name)
  571. return []
  572. def spawn_later(seconds, target, *args, **kwargs):
  573. def wrap(*args, **kwargs):
  574. __import__('time').sleep(seconds)
  575. return target(*args, **kwargs)
  576. return __import__('thread').start_new_thread(wrap, args, kwargs)
  577. def is_clienthello(data):
  578. if len(data) < 20:
  579. return False
  580. if data.startswith('\x16\x03'):
  581. # TLSv12/TLSv11/TLSv1/SSLv3
  582. length, = struct.unpack('>h', data[3:5])
  583. return len(data) == 5 + length
  584. elif data[0] == '\x80' and data[2:4] == '\x01\x03':
  585. # SSLv23
  586. return len(data) == 2 + ord(data[1])
  587. else:
  588. return False
  589. def extract_sni_name(packet):
  590. if packet.startswith('\x16\x03'):
  591. stream = io.BytesIO(packet)
  592. stream.read(0x2b)
  593. session_id_length = ord(stream.read(1))
  594. stream.read(session_id_length)
  595. cipher_suites_length, = struct.unpack('>h', stream.read(2))
  596. stream.read(cipher_suites_length+2)
  597. extensions_length, = struct.unpack('>h', stream.read(2))
  598. extensions = {}
  599. while True:
  600. data = stream.read(2)
  601. if not data:
  602. break
  603. etype, = struct.unpack('>h', data)
  604. elen, = struct.unpack('>h', stream.read(2))
  605. edata = stream.read(elen)
  606. if etype == 0:
  607. server_name = edata[5:]
  608. return server_name
  609. class URLFetch(object):
  610. """URLFetch for gae/php fetchservers"""
  611. skip_headers = frozenset(['Vary', 'Via', 'X-Forwarded-For', 'Proxy-Authorization', 'Proxy-Connection', 'Upgrade', 'X-Chrome-Variations', 'Connection', 'Cache-Control'])
  612. def __init__(self, handler, fetchserver):
  613. assert isinstance(fetchserver, basestring) and callable(create_http_request)
  614. self.handler = handler
  615. self.fetchserver = fetchserver
  616. self.create_http_request = handler.create_http_request
  617. def fetch(self, method, url, headers, body, timeout, **kwargs):
  618. return self.__google_fetch(method, url, headers, body, timeout, **kwargs)
  619. def __google_fetch(self, method, url, headers, body, timeout, **kwargs):
  620. url = url.replace('http://', 'https://', 1)
  621. url = re.sub(r'^(\w+://)', r'\g<1>2-ps.googleusercontent.com/h/', url)
  622. #print url
  623. proxies = {'http':'%s:%s'%('127.0.0.1', common.LISTEN_PORT),'https':'%s:%s'%('127.0.0.1', common.LISTEN_PORT)}
  624. opener = urllib2.build_opener(urllib2.ProxyHandler(proxies))
  625. response = opener.open(url)
  626. #print response
  627. return response
  628. class BaseProxyHandlerFilter(object):
  629. """base proxy handler filter"""
  630. def filter(self, handler):
  631. raise NotImplementedError
  632. class SimpleProxyHandlerFilter(BaseProxyHandlerFilter):
  633. """simple proxy handler filter"""
  634. def filter(self, handler):
  635. if handler.command == 'CONNECT':
  636. return [handler.FORWARD, handler.host, handler.port, handler.connect_timeout]
  637. else:
  638. return [handler.DIRECT, {}]
  639. class SimpleProxyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
  640. """SimpleProxyHandler for GoAgent 3.x"""
  641. protocol_version = 'HTTP/1.1'
  642. ssl_version = ssl.PROTOCOL_SSLv23
  643. disable_transport_ssl = True
  644. scheme = 'http'
  645. skip_headers = frozenset(['Vary', 'Via', 'X-Forwarded-For', 'Proxy-Authorization', 'Proxy-Connection', 'Upgrade', 'X-Chrome-Variations', 'Connection', 'Cache-Control'])
  646. bufsize = 256 * 1024
  647. max_timeout = 4
  648. connect_timeout = 4
  649. first_run_lock = threading.Lock()
  650. handler_filters = [SimpleProxyHandlerFilter()]
  651. sticky_filter = None
  652. def finish(self):
  653. """make python2 BaseHTTPRequestHandler happy"""
  654. try:
  655. BaseHTTPServer.BaseHTTPRequestHandler.finish(self)
  656. except NetWorkIOError as e:
  657. if e[0] not in (errno.ECONNABORTED, errno.ECONNRESET, errno.EPIPE):
  658. raise
  659. def address_string(self):
  660. return '%s:%s' % self.client_address[:2]
  661. def send_response(self, code, message=None):
  662. if message is None:
  663. if code in self.responses:
  664. message = self.responses[code][0]
  665. else:
  666. message = ''
  667. if self.request_version != 'HTTP/0.9':
  668. self.wfile.write('%s %d %s\r\n' % (self.protocol_version, code, message))
  669. def send_header(self, keyword, value):
  670. """Send a MIME header."""
  671. base_send_header = BaseHTTPServer.BaseHTTPRequestHandler.send_header
  672. keyword = keyword.title()
  673. if keyword == 'Set-Cookie':
  674. for cookie in re.split(r', (?=[^ =]+(?:=|$))', value):
  675. base_send_header(self, keyword, cookie)
  676. elif keyword == 'Content-Disposition' and '"' not in value:
  677. value = re.sub(r'filename=([^"\']+)', 'filename="\\1"', value)
  678. base_send_header(self, keyword, value)
  679. else:
  680. base_send_header(self, keyword, value)
  681. def setup(self):
  682. if isinstance(self.__class__.first_run, collections.Callable):
  683. try:
  684. with self.__class__.first_run_lock:
  685. if isinstance(self.__class__.first_run, collections.Callable):
  686. self.first_run()
  687. self.__class__.first_run = None
  688. except StandardError as e:
  689. logging.exception('%s.first_run() return %r', self.__class__, e)
  690. self.__class__.setup = BaseHTTPServer.BaseHTTPRequestHandler.setup
  691. self.__class__.do_CONNECT = self.__class__.do_METHOD
  692. self.__class__.do_GET = self.__class__.do_METHOD
  693. self.__class__.do_PUT = self.__class__.do_METHOD
  694. self.__class__.do_POST = self.__class__.do_METHOD
  695. self.__class__.do_HEAD = self.__class__.do_METHOD
  696. self.__class__.do_DELETE = self.__class__.do_METHOD
  697. self.__class__.do_OPTIONS = self.__class__.do_METHOD
  698. self.setup()
  699. def handle_one_request(self):
  700. if not self.disable_transport_ssl and self.scheme == 'http':
  701. leadbyte = self.connection.recv(1, socket.MSG_PEEK)
  702. if leadbyte in ('\x80', '\x16'):
  703. server_name = ''
  704. if leadbyte == '\x16':
  705. for _ in xrange(2):
  706. leaddata = self.connection.recv(1024, socket.MSG_PEEK)
  707. if is_clienthello(leaddata):
  708. try:
  709. server_name = extract_sni_name(leaddata)
  710. finally:
  711. break
  712. try:
  713. certfile = CertUtil.get_cert(server_name or 'www.google.com')
  714. ssl_sock = ssl.wrap_socket(self.connection, ssl_version=self.ssl_version, keyfile=certfile, certfile=certfile, server_side=True)
  715. except StandardError as e:
  716. if e.args[0] not in (errno.ECONNABORTED, errno.ECONNRESET):
  717. logging.exception('ssl.wrap_socket(self.connection=%r) failed: %s', self.connection, e)
  718. return
  719. self.connection = ssl_sock
  720. self.rfile = self.connection.makefile('rb', self.bufsize)
  721. self.wfile = self.connection.makefile('wb', 0)
  722. self.scheme = 'https'
  723. return BaseHTTPServer.BaseHTTPRequestHandler.handle_one_request(self)
  724. def first_run(self):
  725. pass
  726. def gethostbyname2(self, hostname):
  727. return socket.gethostbyname_ex(hostname)[-1]
  728. def create_tcp_connection(self, hostname, port, timeout, **kwargs):
  729. return socket.create_connection((hostname, port), timeout)
  730. def create_ssl_connection(self, hostname, port, timeout, **kwargs):
  731. sock = self.create_tcp_connection(hostname, port, timeout, **kwargs)
  732. ssl_sock = ssl.wrap_socket(sock, ssl_version=self.ssl_version)
  733. return ssl_sock
  734. def create_http_request(self, method, url, headers, body, timeout, **kwargs):
  735. scheme, netloc, path, query, _ = urlparse.urlsplit(url)
  736. if netloc.rfind(':') <= netloc.rfind(']'):
  737. # no port number
  738. host = netloc
  739. port = 443 if scheme == 'https' else 80
  740. else:
  741. host, _, port = netloc.rpartition(':')
  742. port = int(port)
  743. if query:
  744. path += '?' + query
  745. if 'Host' not in headers:
  746. headers['Host'] = host
  747. if body and 'Content-Length' not in headers:
  748. headers['Content-Length'] = str(len(body))
  749. ConnectionType = httplib.HTTPSConnection if scheme == 'https' else httplib.HTTPConnection
  750. connection = ConnectionType(netloc, timeout=timeout)
  751. connection.request(method, path, body=body, headers=headers)
  752. response = connection.getresponse()
  753. return response
  754. def create_http_request_withserver(self, fetchserver, method, url, headers, body, timeout, **kwargs):
  755. return URLFetch(self, fetchserver).fetch(method, url, headers, body, timeout, **kwargs)
  756. def handle_urlfetch_error(self, fetchserver, response):
  757. pass
  758. def handle_urlfetch_response_close(self, fetchserver, response):
  759. pass
  760. def parse_header(self):
  761. if self.command == 'CONNECT':
  762. netloc = self.path
  763. elif self.path[0] == '/':
  764. netloc = self.headers.get('Host', 'localhost')
  765. self.path = '%s://%s%s' % (self.scheme, netloc, self.path)
  766. else:
  767. netloc = urlparse.urlsplit(self.path).netloc
  768. m = re.match(r'^(.+):(\d+)$', netloc)
  769. if m:
  770. self.host = m.group(1).strip('[]')
  771. self.port = int(m.group(2))
  772. else:
  773. self.host = netloc
  774. self.port = 443 if self.scheme == 'https' else 80
  775. def forward_socket(self, local, remote, timeout):
  776. try:
  777. tick = 1
  778. bufsize = self.bufsize
  779. timecount = timeout
  780. while 1:
  781. timecount -= tick
  782. if timecount <= 0:
  783. break
  784. (ins, _, errors) = select.select([local, remote], [], [local, remote], tick)
  785. if errors:
  786. break
  787. for sock in ins:
  788. data = sock.recv(bufsize)
  789. if not data:
  790. break
  791. if sock is remote:
  792. local.sendall(data)
  793. timecount = timeout
  794. else:
  795. remote.sendall(data)
  796. timecount = timeout
  797. except socket.timeout:
  798. pass
  799. except NetWorkIOError as e:
  800. if e.args[0] not in (errno.ECONNABORTED, errno.ECONNRESET, errno.ENOTCONN, errno.EPIPE):
  801. raise
  802. if e.args[0] in (errno.EBADF,):
  803. return
  804. finally:
  805. for sock in (remote, local):
  806. try:
  807. sock.close()
  808. except StandardError:
  809. pass
  810. def MOCK(self, status, headers, content):
  811. """mock response"""
  812. logging.info('%s "MOCK %s %s %s" %d %d', self.address_string(), self.command, self.path, self.protocol_version, status, len(content))
  813. headers = dict((k.title(), v) for k, v in headers.items())
  814. if 'Transfer-Encoding' in headers:
  815. del headers['Transfer-Encoding']
  816. if 'Content-Length' not in headers:
  817. headers['Content-Length'] = len(content)
  818. if 'Connection' not in headers:
  819. headers['Connection'] = 'close'
  820. self.send_response(status)
  821. for key, value in headers.items():
  822. self.send_header(key, value)
  823. self.end_headers()
  824. self.wfile.write(content)
  825. def STRIP(self, do_ssl_handshake=True, sticky_filter=None):
  826. """strip connect"""
  827. certfile = CertUtil.get_cert(self.host)
  828. logging.info('%s "STRIP %s %s:%d %s" - -', self.address_string(), self.command, self.host, self.port, self.protocol_version)
  829. self.send_response(200)
  830. self.end_headers()
  831. if do_ssl_handshake:
  832. try:
  833. ssl_sock = ssl.wrap_socket(self.connection, ssl_version=self.ssl_version, keyfile=certfile, certfile=certfile, server_side=True)
  834. except StandardError as e:
  835. if e.args[0] not in (errno.ECONNABORTED, errno.ECONNRESET):
  836. logging.exception('ssl.wrap_socket(self.connection=%r) failed: %s', self.connection, e)
  837. return
  838. self.connection = ssl_sock
  839. self.rfile = self.connection.makefile('rb', self.bufsize)
  840. self.wfile = self.connection.makefile('wb', 0)
  841. self.scheme = 'https'
  842. try:
  843. self.raw_requestline = self.rfile.readline(65537)
  844. if len(self.raw_requestline) > 65536:
  845. self.requestline = ''
  846. self.request_version = ''
  847. self.command = ''
  848. self.send_error(414)
  849. return
  850. if not self.raw_requestline:
  851. self.close_connection = 1
  852. return
  853. if not self.parse_request():
  854. return
  855. except NetWorkIOError as e:
  856. if e.args[0] not in (errno.ECONNABORTED, errno.ECONNRESET, errno.EPIPE):
  857. raise
  858. self.sticky_filter = sticky_filter
  859. try:
  860. self.do_METHOD()
  861. except NetWorkIOError as e:
  862. if e.args[0] not in (errno.ECONNABORTED, errno.ETIMEDOUT, errno.EPIPE):
  863. raise
  864. def FORWARD(self, hostname, port, timeout, kwargs={}):
  865. """forward socket"""
  866. do_ssl_handshake = kwargs.pop('do_ssl_handshake', False)
  867. local = self.connection
  868. remote = None
  869. self.send_response(200)
  870. self.end_headers()
  871. self.close_connection = 1
  872. data = local.recv(1024)
  873. if not data:
  874. local.close()
  875. return
  876. data_is_clienthello = is_clienthello(data)
  877. if data_is_clienthello:
  878. kwargs['client_hello'] = data
  879. max_retry = kwargs.get('max_retry', 5)
  880. for i in xrange(max_retry):
  881. try:
  882. if do_ssl_handshake:
  883. remote = self.create_ssl_connection(hostname, port, timeout, **kwargs)
  884. else:
  885. remote = self.create_tcp_connection(hostname, port, timeout, **kwargs)
  886. if not data_is_clienthello and remote and not isinstance(remote, Exception):
  887. remote.sendall(data)
  888. break
  889. except StandardError as e:
  890. logging.exception('%s "FWD %s %s:%d %s" %r', self.address_string(), self.command, hostname, port, self.protocol_version, e)
  891. if hasattr(remote, 'close'):
  892. remote.close()
  893. if i == max_retry - 1:
  894. raise
  895. logging.info('%s "FWD %s %s:%d %s" - -', self.address_string(), self.command, hostname, port, self.protocol_version)
  896. if hasattr(remote, 'fileno'):
  897. # reset timeout default to avoid long http upload failure, but it will delay timeout retry :(
  898. remote.settimeout(None)
  899. del kwargs
  900. data = data_is_clienthello and getattr(remote, 'data', None)
  901. if data:
  902. del remote.data
  903. local.sendall(data)
  904. self.forward_socket(local, remote, self.max_timeout)
  905. def DIRECT(self, kwargs):
  906. method = self.command
  907. if 'url' in kwargs:
  908. url = kwargs.pop('url')
  909. elif self.path.lower().startswith(('http://', 'https://', 'ftp://')):
  910. url = self.path
  911. else:
  912. url = 'http://%s%s' % (self.headers['Host'], self.path)
  913. headers = dict((k.title(), v) for k, v in self.headers.items())
  914. body = self.body
  915. response = None
  916. try:
  917. response = self.create_http_request(method, url, headers, body, timeout=self.connect_timeout, **kwargs)
  918. logging.info('%s "DIRECT %s %s %s" %s %s', self.address_string(), self.command, url, self.protocol_version, response.status, response.getheader('Content-Length', '-'))
  919. response_headers = dict((k.title(), v) for k, v in response.getheaders())
  920. self.send_response(response.status)
  921. for key, value in response.getheaders():
  922. self.send_header(key, value)
  923. self.end_headers()
  924. if self.command == 'HEAD' or response.status in (204, 304):
  925. response.close()
  926. return
  927. need_chunked = 'Transfer-Encoding' in response_headers
  928. while True:
  929. data = response.read(8192)
  930. if not data:
  931. if need_chunked:
  932. self.wfile.write('0\r\n\r\n')
  933. break
  934. if need_chunked:
  935. self.wfile.write('%x\r\n' % len(data))
  936. self.wfile.write(data)
  937. if need_chunked:
  938. self.wfile.write('\r\n')
  939. del data
  940. except (ssl.SSLError, socket.timeout, socket.error):
  941. if response:
  942. if response.fp and response.fp._sock:
  943. response.fp._sock.close()
  944. response.close()
  945. finally:
  946. if response:
  947. response.close()
  948. def URLFETCH(self, fetchservers, max_retry=5, kwargs={}):
  949. """urlfetch from fetchserver"""
  950. method = self.command
  951. if self.path[0] == '/':
  952. url = '%s://%s%s' % (self.scheme, self.headers['Host'], self.path)
  953. elif self.path.lower().startswith(('http://', 'https://', 'ftp://')):
  954. url = self.path
  955. else:
  956. raise ValueError('URLFETCH %r is not a valid url' % self.path)
  957. headers = dict((k.title(), v) for k, v in self.headers.items())
  958. body = self.body
  959. response = None
  960. errors = []
  961. fetchserver = ''
  962. for i in xrange(max_retry):
  963. try:
  964. response = self.create_http_request_withserver(fetchserver, method, url, headers, body, timeout=60, **kwargs)
  965. if response:
  966. break
  967. except StandardError as e:
  968. errors.append(e)
  969. logging.info('URLFETCH "%s %s" fetchserver=%r %r, retry...', method, url, fetchserver, e)
  970. #logging.info('%s "URL %s %s %s" %s %s', self.address_string(), method, url, self.protocol_version, response.status, response.getheader('Content-Length', '-'))
  971. try:
  972. bufsize = 8192
  973. while True:
  974. data = response.read(bufsize)
  975. if data:
  976. self.wfile.write(data)
  977. #print 'read'
  978. if not data:
  979. self.handle_urlfetch_response_close(fetchserver, response)
  980. response.close()
  981. break
  982. del data
  983. except NetWorkIOError as e:
  984. if e[0] in (errno.ECONNABORTED, errno.EPIPE) or 'bad write retry' in repr(e):
  985. return
  986. def do_METHOD(self):
  987. self.parse_header()
  988. self.body = self.rfile.read(int(self.headers['Content-Length'])) if 'Content-Length' in self.headers else ''
  989. if self.sticky_filter:
  990. action = self.sticky_filter.filter(self)
  991. if action:
  992. return action.pop(0)(*action)
  993. for handler_filter in self.handler_filters:
  994. action = handler_filter.filter(self)
  995. if action:
  996. return action.pop(0)(*action)
  997. class AdvancedProxyHandler(SimpleProxyHandler):
  998. """Advanced Proxy Handler"""
  999. dns_cache = LRUCache(64*1024)
  1000. dns_servers = []
  1001. dns_blacklist = []
  1002. tcp_connection_time = collections.defaultdict(float)
  1003. tcp_connection_time_with_clienthello = collections.defaultdict(float)
  1004. tcp_connection_cache = collections.defaultdict(Queue.PriorityQueue)
  1005. ssl_connection_time = collections.defaultdict(float)
  1006. ssl_connection_cache = collections.defaultdict(Queue.PriorityQueue)
  1007. ssl_connection_good_ipaddrs = {}
  1008. ssl_connection_bad_ipaddrs = {}
  1009. ssl_connection_unknown_ipaddrs = {}
  1010. ssl_connection_keepalive = False
  1011. max_window = 4
  1012. openssl_context = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_METHOD)
  1013. def gethostbyname2(self, hostname):
  1014. try:
  1015. iplist = self.dns_cache[hostname]
  1016. except KeyError:
  1017. if re.match(r'^\d+\.\d+\.\d+\.\d+$', hostname) or ':' in hostname:
  1018. iplist = [hostname]
  1019. elif self.dns_servers:
  1020. try:
  1021. record = dnslib_resolve_over_udp(hostname, self.dns_servers, timeout=2, blacklist=self.dns_blacklist)
  1022. except socket.gaierror:
  1023. record = dnslib_resolve_over_tcp(hostname, self.dns_servers, timeout=2, blacklist=self.dns_blacklist)
  1024. iplist = dnslib_record2iplist(record)
  1025. else:
  1026. iplist = socket.gethostbyname_ex(hostname)[-1]
  1027. self.dns_cache[hostname] = iplist
  1028. return iplist
  1029. def create_tcp_connection(self, hostname, port, timeout, **kwargs):
  1030. client_hello = kwargs.get('client_hello', None)
  1031. cache_key = kwargs.get('cache_key') if not client_hello else None
  1032. def create_connection(ipaddr, timeout, queobj):
  1033. sock = None
  1034. try:
  1035. # create a ipv4/ipv6 socket object
  1036. sock = socket.socket(socket.AF_INET if ':' not in ipaddr[0] else socket.AF_INET6)
  1037. # set reuseaddr option to avoid 10048 socket error
  1038. sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  1039. # resize socket recv buffer 8K->32K to improve browser releated application performance
  1040. sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 32*1024)
  1041. # disable nagle algorithm to send http request quickly.
  1042. sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, True)
  1043. # set a short timeout to trigger timeout retry more quickly.
  1044. sock.settimeout(min(self.connect_timeout, timeout))
  1045. # start connection time record
  1046. start_time = time.time()
  1047. # TCP connect
  1048. sock.connect(ipaddr)
  1049. # record TCP connection time
  1050. self.tcp_connection_time[ipaddr] = time.time() - start_time
  1051. # send client hello and peek server hello
  1052. if client_hello:
  1053. sock.sendall(client_hello)
  1054. if gevent and isinstance(sock, gevent.socket.socket):
  1055. sock.data = data = sock.recv(4096)
  1056. else:
  1057. data = sock.recv(4096, socket.MSG_PEEK)
  1058. if not data:
  1059. logging.debug('create_tcp_connection %r with client_hello return NULL byte, continue %r', ipaddr, time.time()-start_time)
  1060. raise socket.timeout('timed out')
  1061. # record TCP connection time with client hello
  1062. self.tcp_connection_time_with

Large files files are truncated, but you can click here to view the full file