PageRenderTime 50ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/code/default/smart_router/local/smart_route.py

https://gitlab.com/Mirros/XX-net
Python | 545 lines | 539 code | 6 blank | 0 comment | 4 complexity | ba8021dbc8044ece869843f5c7cb3734 MD5 | raw file
  1. import time
  2. import socket
  3. import struct
  4. import urlparse
  5. import io
  6. import ssl
  7. import OpenSSL
  8. import utils
  9. import simple_http_server
  10. from socket_wrap import SocketWrap
  11. import global_var as g
  12. import socks
  13. from xlog import getLogger
  14. xlog = getLogger("smart_router")
  15. SO_ORIGINAL_DST = 80
  16. fake_host = ""
  17. class DontFakeCA(Exception):
  18. pass
  19. class ConnectFail(Exception):
  20. pass
  21. class RedirectHttpsFail(Exception):
  22. pass
  23. class SniNotExist(Exception):
  24. pass
  25. class NotSupported(Exception):
  26. def __init__(self, req, sock):
  27. self.req = req
  28. self.sock = sock
  29. class SslWrapFail(Exception):
  30. pass
  31. class XTunnelNotRunning(Exception):
  32. pass
  33. def is_gae_workable():
  34. if not g.gae_proxy:
  35. return False
  36. return g.gae_proxy.apis.is_workable()
  37. def is_x_tunnel_workable():
  38. if not g.x_tunnel:
  39. return False
  40. return g.x_tunnel.apis.is_workable()
  41. def is_clienthello(data):
  42. if len(data) < 20:
  43. return False
  44. if data.startswith('\x16\x03'):
  45. # TLSv12/TLSv11/TLSv1/SSLv3
  46. length, = struct.unpack('>h', data[3:5])
  47. return len(data) == 5 + length
  48. elif data[0] == '\x80' and data[2:4] == '\x01\x03':
  49. # SSLv23
  50. return len(data) == 2 + ord(data[1])
  51. else:
  52. return False
  53. def have_ipv6(ips):
  54. for ip in ips:
  55. if ":" in ip:
  56. return True
  57. return False
  58. def extract_sni_name(packet):
  59. if not packet.startswith('\x16\x03'):
  60. return
  61. stream = io.BytesIO(packet)
  62. stream.read(0x2b)
  63. session_id_length = ord(stream.read(1))
  64. stream.read(session_id_length)
  65. cipher_suites_length, = struct.unpack('>h', stream.read(2))
  66. stream.read(cipher_suites_length+2)
  67. extensions_length, = struct.unpack('>h', stream.read(2))
  68. # extensions = {}
  69. while True:
  70. data = stream.read(2)
  71. if not data:
  72. break
  73. etype, = struct.unpack('>h', data)
  74. elen, = struct.unpack('>h', stream.read(2))
  75. edata = stream.read(elen)
  76. if etype == 0:
  77. server_name = edata[5:]
  78. return server_name
  79. def netloc_to_host_port(netloc, default_port=80):
  80. if ":" in netloc:
  81. host, _, port = netloc.rpartition(':')
  82. port = int(port)
  83. else:
  84. host = netloc
  85. port = default_port
  86. return host, port
  87. def get_sni(sock, left_buf=""):
  88. if left_buf:
  89. leadbyte = left_buf[0]
  90. else:
  91. leadbyte = sock.recv(1, socket.MSG_PEEK)
  92. if leadbyte in ('\x80', '\x16'):
  93. if leadbyte == '\x16':
  94. for _ in xrange(2):
  95. leaddata = left_buf + sock.recv(1024, socket.MSG_PEEK)
  96. if is_clienthello(leaddata):
  97. try:
  98. server_name = extract_sni_name(leaddata)
  99. return server_name
  100. except:
  101. break
  102. raise SniNotExist
  103. elif leadbyte not in ["G", "P", "D", "O", "H", "T"]:
  104. raise SniNotExist
  105. leaddata = ""
  106. for _ in xrange(2):
  107. leaddata = left_buf + sock.recv(65535, socket.MSG_PEEK)
  108. if leaddata:
  109. break
  110. else:
  111. time.sleep(0.1)
  112. continue
  113. if not leaddata:
  114. raise SniNotExist
  115. n1 = leaddata.find("\r\n")
  116. if n1 <= -1:
  117. raise SniNotExist
  118. req_line = leaddata[:n1]
  119. words = req_line.split()
  120. if len(words) == 3:
  121. method, url, http_version = words
  122. elif len(words) == 2:
  123. method, url = words
  124. http_version = "HTTP/1.1"
  125. else:
  126. raise SniNotExist
  127. if method not in ["GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS", "TRACE", "PATCH"]:
  128. raise SniNotExist
  129. n2 = leaddata.find("\r\n\r\n", n1)
  130. if n2 <= -1:
  131. raise SniNotExist
  132. header_block = leaddata[n1+2:n2]
  133. lines = header_block.split("\r\n")
  134. # path = url
  135. host = None
  136. for line in lines:
  137. key, _, value = line.rpartition(":")
  138. value = value.strip()
  139. if key.lower() == "host":
  140. host, port = netloc_to_host_port(value)
  141. break
  142. if host is None:
  143. raise SniNotExist
  144. return host
  145. def do_direct(sock, host, ips, port, client_address, left_buf=""):
  146. if not g.config.auto_direct:
  147. raise ConnectFail()
  148. remote_sock = g.connect_manager.get_conn(host, ips, port)
  149. if not remote_sock:
  150. raise ConnectFail()
  151. xlog.debug("host:%s:%d direct connect %s success", host, port, remote_sock.ip)
  152. if left_buf:
  153. remote_sock.send(left_buf)
  154. g.pipe_socks.add_socks(sock, remote_sock)
  155. def do_redirect_https(sock, host, ips, port, client_address, left_buf=""):
  156. if not g.config.auto_direct:
  157. raise ConnectFail()
  158. remote_sock = g.connect_manager.get_conn(host, ips, 443)
  159. if not remote_sock:
  160. raise RedirectHttpsFail()
  161. try:
  162. ssl_sock = ssl.wrap_socket(remote_sock._sock)
  163. except Exception as e:
  164. raise RedirectHttpsFail()
  165. xlog.debug("host:%s:%d redirect_https connect %s success", host, port, remote_sock.ip)
  166. if left_buf:
  167. ssl_sock.send(left_buf)
  168. sw = SocketWrap(ssl_sock, remote_sock.ip, port, host)
  169. sock.recved_times = 3
  170. g.pipe_socks.add_socks(sock, sw)
  171. def do_socks(sock, host, port, client_address, left_buf=""):
  172. if not g.x_tunnel:
  173. raise XTunnelNotRunning()
  174. try:
  175. conn_id = g.x_tunnel.proxy_session.create_conn(sock, host, port)
  176. except Exception as e:
  177. xlog.warn("do_sock to %s:%d, x_tunnel fail:%r", host, port, e)
  178. raise XTunnelNotRunning()
  179. if not conn_id:
  180. xlog.warn("x_tunnel create conn fail")
  181. raise XTunnelNotRunning()
  182. # xlog.debug("do_socks %r connect to %s:%d conn_id:%d", client_address, host, port, conn_id)
  183. if left_buf:
  184. g.x_tunnel.global_var.session.conn_list[conn_id].transfer_received_data(left_buf)
  185. g.x_tunnel.global_var.session.conn_list[conn_id].start(block=True)
  186. def do_unwrap_socks(sock, host, port, client_address, req, left_buf=""):
  187. if not g.x_tunnel:
  188. return
  189. try:
  190. remote_sock = socks.create_connection(
  191. (host, port),
  192. proxy_type="socks5h", proxy_addr="127.0.0.1", proxy_port=1080, timeout=15
  193. )
  194. except Exception as e:
  195. xlog.warn("do_unwrap_socks connect to x-tunnel for %s:%d proxy fail.", host, port)
  196. return
  197. if isinstance(req.connection, ssl.SSLSocket):
  198. try:
  199. # TODO: send SNI
  200. remote_ssl_sock = ssl.wrap_socket(remote_sock)
  201. except:
  202. xlog.warn("do_unwrap_socks ssl_wrap for %s:%d proxy fail.", host, port)
  203. return
  204. else:
  205. remote_ssl_sock = remote_sock
  206. # avoid close by req.__del__
  207. req.rfile._close = False
  208. req.wfile._close = False
  209. req.connection = None
  210. if not isinstance(sock, SocketWrap):
  211. sock = SocketWrap(sock, client_address[0], client_address[1])
  212. xlog.info("host:%s:%d do_unwrap_socks", host, port)
  213. remote_ssl_sock.send(left_buf)
  214. sw = SocketWrap(remote_ssl_sock, "x-tunnel", port, host)
  215. sock.recved_times = 3
  216. g.pipe_socks.add_socks(sock, sw)
  217. def do_gae(sock, host, port, client_address, left_buf=""):
  218. sock.setblocking(1)
  219. if left_buf:
  220. schema = "http"
  221. else:
  222. leadbyte = sock.recv(1, socket.MSG_PEEK)
  223. if leadbyte in ('\x80', '\x16'):
  224. if host != fake_host and not g.config.enable_fake_ca:
  225. raise DontFakeCA()
  226. try:
  227. sock._sock = g.gae_proxy.proxy_handler.wrap_ssl(sock._sock, host, port, client_address)
  228. except Exception as e:
  229. raise SslWrapFail()
  230. schema = "https"
  231. else:
  232. schema = "http"
  233. sock.setblocking(1)
  234. xlog.debug("host:%s:%d do gae", host, port)
  235. req = g.gae_proxy.proxy_handler.GAEProxyHandler(sock._sock, client_address, None, xlog)
  236. req.parse_request()
  237. if req.path[0] == '/':
  238. url = '%s://%s%s' % (schema, req.headers['Host'], req.path)
  239. else:
  240. url = req.path
  241. if url in ["http://www.twitter.com/xxnet",
  242. "https://www.twitter.com/xxnet",
  243. "http://www.deja.com/xxnet",
  244. "https://www.deja.com/xxnet"
  245. ]:
  246. # for web_ui status page
  247. # auto detect browser proxy setting is work
  248. xlog.debug("CONNECT %s %s", req.command, req.path)
  249. req.wfile.write(req.self_check_response_data)
  250. return
  251. if req.upgrade == "websocket":
  252. xlog.debug("gae %s not support WebSocket", req.path)
  253. raise NotSupported(req, sock)
  254. if len(req.path) >= 2048:
  255. xlog.debug("gae %s path len exceed 1024 limit", req.path)
  256. raise NotSupported(req, sock)
  257. if req.command not in ["GET", "PUT", "POST", "DELETE", "PATCH", "HEAD", "OPTIONS"]:
  258. xlog.debug("gae %s %s, method not supported", req.command, req.path)
  259. raise NotSupported(req, sock)
  260. req.parsed_url = urlparse.urlparse(req.path)
  261. req.do_METHOD()
  262. def try_loop(scense, rule_list, sock, host, port, client_address, left_buf=""):
  263. start_time = time.time()
  264. for rule in rule_list:
  265. try:
  266. if rule == "redirect_https":
  267. if port != 80:
  268. continue
  269. ips = g.dns_srv.query(host)
  270. do_redirect_https(sock, host, ips, port, client_address, left_buf)
  271. xlog.info("%s %s:%d redirect_https", scense, host, port)
  272. return
  273. elif rule == "direct":
  274. ips = g.dns_srv.query(host)
  275. do_direct(sock, host, ips, port, client_address, left_buf)
  276. xlog.info("%s %s:%d direct", scense, host, port)
  277. return
  278. elif rule == "gae":
  279. if not is_gae_workable() and host != fake_host:
  280. xlog.debug("%s gae host:%s:%d, but gae not work", scense, host, port)
  281. continue
  282. try:
  283. # sni_host = get_sni(sock, left_buf)
  284. # xlog.info("%s %s:%d try gae", scense, host, port)
  285. do_gae(sock, host, port, client_address, left_buf)
  286. return
  287. except DontFakeCA:
  288. continue
  289. except NotSupported as e:
  290. req = e.req
  291. left_bufs = [req.raw_requestline]
  292. for k in req.headers:
  293. v = req.headers[k]
  294. left_bufs.append("%s: %s\r\n" % (k, v))
  295. left_bufs.append("\r\n")
  296. left_buf = "".join(left_bufs)
  297. return do_unwrap_socks(e.sock, host, port, client_address, req, left_buf=left_buf)
  298. except SniNotExist:
  299. xlog.debug("%s domain:%s get sni fail", scense, host)
  300. continue
  301. except (SslWrapFail, simple_http_server.ParseReqFail) as e:
  302. xlog.warn("%s domain:%s fail:%r", scense, host, e)
  303. g.domain_cache.report_gae_deny(host, port)
  304. sock.close()
  305. return
  306. except simple_http_server.GetReqTimeout:
  307. # Happen sometimes, don't known why.
  308. xlog.debug("%s host:%s:%d try gae, GetReqTimeout:%d", scense, host, port,
  309. (time.time() - start_time) * 1000)
  310. sock.close()
  311. return
  312. except Exception as e:
  313. xlog.exception("%s host:%s:%d rule:%s except:%r", scense, host, port, rule, e)
  314. g.domain_cache.report_gae_deny(host, port)
  315. sock.close()
  316. return
  317. elif rule == "socks":
  318. xlog.info("%s %s:%d socks", scense, host, port)
  319. do_socks(sock, host, port, client_address, left_buf)
  320. return
  321. elif rule == "black":
  322. xlog.info("%s to:%s:%d black", scense, host, port)
  323. sock.close()
  324. return
  325. else:
  326. xlog.error("%s %s:%d rule:%s unknown", scense, host, port, host, rule)
  327. sock.close()
  328. return
  329. except Exception as e:
  330. xlog.debug("%s %s to %s:%d except:%r", scense, rule, host, port, e)
  331. xlog.info("%s %s to %s:%d fail", scense, rule_list, host, port)
  332. sock.close()
  333. return
  334. def handle_ip_proxy(sock, ip, port, client_address):
  335. if not isinstance(sock, SocketWrap):
  336. sock = SocketWrap(sock, client_address[0], client_address[1])
  337. rule = g.user_rules.check_host(ip, port)
  338. if not rule:
  339. if utils.is_private_ip(ip):
  340. rule = "direct"
  341. if rule:
  342. return try_loop("ip user", [rule], sock, ip, port, client_address)
  343. if g.config.auto_direct and g.ip_region.check_ip(ip):
  344. rule_list = ["direct", "gae", "socks", "redirect_https"]
  345. else:
  346. if g.config.auto_direct or g.config.auto_gae:
  347. try:
  348. host = get_sni(sock)
  349. if host:
  350. return handle_domain_proxy(sock, host, port, client_address)
  351. except SniNotExist as e:
  352. xlog.debug("ip:%s:%d get sni fail", ip, port)
  353. if not g.config.auto_direct:
  354. rule_list = ["socks"]
  355. else:
  356. record = g.ip_cache.get(ip)
  357. if record and record["r"] == "socks":
  358. rule_list = ["socks"]
  359. else:
  360. rule_list = ["direct", "socks"]
  361. if not g.config.auto_direct and "direct" in rule_list:
  362. try:
  363. rule_list.remove("direct")
  364. rule_list.remove("redirect_https")
  365. except:
  366. pass
  367. if not g.config.auto_gae and "gae" in rule_list:
  368. try:
  369. rule_list.remove("gae")
  370. except:
  371. pass
  372. try_loop("ip", rule_list, sock, ip, port, client_address)
  373. def handle_domain_proxy(sock, host, port, client_address, left_buf=""):
  374. global fake_host
  375. if not fake_host and g.gae_proxy:
  376. fake_host = g.gae_proxy.web_control.get_fake_host()
  377. if not isinstance(sock, SocketWrap):
  378. sock = SocketWrap(sock, client_address[0], client_address[1])
  379. sock.target = "%s:%d" % (host, port)
  380. rule = g.user_rules.check_host(host, port)
  381. if not rule:
  382. if host == fake_host:
  383. rule = "gae"
  384. elif utils.check_ip_valid(host) and utils.is_private_ip(host):
  385. rule = "direct"
  386. if rule:
  387. return try_loop("domain user", [rule], sock, host, port, client_address, left_buf)
  388. if g.config.block_advertisement and g.gfwlist.is_advertisement(host):
  389. xlog.info("block advertisement %s:%d", host, port)
  390. sock.close()
  391. return
  392. #ips = g.dns_srv.query(host)
  393. #if check_local_network.IPv6.is_ok() and have_ipv6(ips) and port == 443:
  394. # rule_list = ["direct", "gae", "socks", "redirect_https"]
  395. # gae is more faster then direct.
  396. record = g.domain_cache.get(host)
  397. if record and record["r"] != "unknown":
  398. rule = record["r"]
  399. if rule == "gae":
  400. rule_list = ["gae", "socks", "redirect_https", "direct"]
  401. else:
  402. rule_list = ["direct", "gae", "socks", "redirect_https"]
  403. if not g.domain_cache.accept_gae(host):
  404. rule_list.remove("gae")
  405. elif g.gfwlist.is_white(host):
  406. rule_list = ["direct", "gae", "socks", "redirect_https"]
  407. elif g.gfwlist.check(host):
  408. rule_list = ["gae", "socks", "redirect_https", "direct"]
  409. else:
  410. ips = g.dns_srv.query(host)
  411. if g.ip_region.check_ips(ips):
  412. rule_list = ["direct", "gae", "socks", "redirect_https"]
  413. else:
  414. rule_list = ["gae", "socks", "redirect_https", "direct"]
  415. if not g.config.auto_direct and "direct" in rule_list:
  416. try:
  417. rule_list.remove("direct")
  418. rule_list.remove("redirect_https")
  419. except:
  420. pass
  421. if not g.config.enable_fake_ca and port == 443 and "gae" in rule_list:
  422. try:
  423. rule_list.remove("gae")
  424. except:
  425. pass
  426. if not g.config.auto_gae and "gae" in rule_list:
  427. try:
  428. rule_list.remove("gae")
  429. except:
  430. pass
  431. try_loop("domain", rule_list, sock, host, port, client_address, left_buf)