-
-
Save pigscanflyyyy/3f28c9fe6f097b61df86468afa7c8b3c to your computer and use it in GitHub Desktop.
create tunnel through http proxy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
import SocketServer | |
import socket | |
import logging | |
import select | |
import threading | |
import signal | |
import argparse | |
import sys | |
def create_tunnel(proxy_host, proxy_port, host, port, listen_port, listen_host=None): | |
class Handler(TunnelHandler): | |
def get_config(self): | |
return (proxy_host, proxy_port, host, port) | |
if listen_host is None: | |
listen_host = 'localhost' | |
server = ThreadingTCPServer((listen_host, listen_port), Handler) | |
return server | |
class ThreadingTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): | |
allow_reuse_address = True | |
is_quiting = False | |
def quit(self): | |
self.is_quiting = True | |
self.shutdown() | |
class TunnelHandler(SocketServer.StreamRequestHandler): | |
def proxy_connect(self): | |
(self.proxy_host, self.proxy_port, self.host, self.port) = self.get_config() | |
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
sock.connect((self.proxy_host, self.proxy_port)) | |
sock.send("CONNECT %s:%d HTTP/1.1\r\nHost:%s:%d\r\n\r\n" % (self.host, self.port, | |
self.host, self.port)) | |
resp = sock.recv(4096) | |
parts = resp.split() | |
if parts[1] != "200": | |
raise Exception("Error response from Proxy server : %s" % resp) | |
return sock | |
def handle(self): | |
try: | |
proxy = self.proxy_connect() | |
self.handle_tcp(self.request, proxy) | |
except socket.error, e: | |
logging.warn(e) | |
def handle_tcp(self, request, proxy): | |
try: | |
fdset = [ request, proxy ] | |
while not self.server.is_quiting: | |
r, w, e = select.select(fdset, [], [], 0.5) | |
if request in r: | |
data = request.recv(4096) | |
if len(data) <= 0: | |
break | |
proxy.send(data) | |
if proxy in r: | |
data = proxy.recv(4096) | |
if len(data) <= 0: | |
break | |
request.send(data) | |
finally: | |
self.server.shutdown_request(request) | |
proxy.close() | |
def validate_args(proxy_str, tunnel_strs): | |
proxy_host, proxy_port = proxy_str.strip().split(":") | |
proxy_port = int(proxy_port) | |
if proxy_port <= 0: | |
sys.stderr.write("Bad proxy specification: %s" % args.proxy) | |
sys.exit(1) | |
tunnels = [] | |
for tunnel_str in tunnel_strs: | |
parts = tunnel_str.strip().split(':') | |
num = len(parts) | |
if num == 3: | |
listen_host = None | |
listen_port, remote_host, remote_port = parts | |
elif num == 4: | |
listen_host, listen_port, remote_host, remote_port = parts | |
else: | |
sys.stderr.write("Bad tunnel specification: %s" % tunnel_str) | |
sys.exit(1) | |
listen_port = int(listen_port) | |
remote_port = int(remote_port) | |
if listen_port <= 0 or remote_port <= 0: | |
sys.stderr.write("Bad tunnel specification: %s" % tunnel_str) | |
tunnels.append([proxy_host, proxy_port, remote_host, remote_port, | |
listen_port, listen_host]) | |
return tunnels | |
def main(): | |
parser = argparse.ArgumentParser() | |
parser.add_argument("proxy", help="proxy_host:proxy_port") | |
parser.add_argument("tunnel", nargs='+', help="[bind_address:]bind_port:remote_host:remote_port") | |
args = parser.parse_args() | |
tunnels = validate_args(args.proxy, args.tunnel) | |
threads = [] | |
for config in tunnels: | |
server = create_tunnel(*config) | |
t = threading.Thread(target=server.serve_forever) | |
t.setDaemon(True) | |
t.start() | |
threads.append((t, server, config)) | |
def signal_handler(signum, frame): | |
for _, server, _ in threads: | |
server.quit() | |
signal.signal(signal.SIGINT, signal_handler) | |
main_thread = threading.currentThread() | |
while threading.activeCount() > 1: | |
for t in threading.enumerate(): | |
if t is main_thread: | |
continue | |
t.join(timeout=0.1) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment