# -*- coding: utf-8 -*-
# 建议 Python 2.6 环境,以支持 https proxy
# Win32 下需安装
# http://www.python.org/ftp/python/2.6.5/python-2.6.5.msi
# http://www.voidspace.org.uk/downloads/pycrypto-2.0.1.win32-py2.6.exe
# 至于 IronPython 目前还没有 server-side ssl 支持,据说 IP 2.6.1 将会有...
try:
from ipcrypto
import descrypto
#IronPython 里的 socket 不支持 bind 到 '0.0.0.0'
import platform
bind_address =
(platform.
node(), 8000
)
except:
from pycrypto
import descrypto
bind_address =
('0.0.0.0', 8000
)
import urllib2
import BaseHTTPServer, SocketServer
#REMOTEURL/PASSWORD 和国外主机配合
REMOTEURL = 'http://www.dup2.org/blarblarblar.php'
PASSWORD = 'yourpasswordhere'
# KEY/CERT 的生成参考 http://docs.python.org/library/ssl.html
KEYFILE = 'cert.pem'
CERTFILE = 'cert.pem'
#自定义允许的IP列表, 给每个IP起个名字帮助记忆
allow_clients = {'127.0.0.1': 'myself'}
desobj = descrypto(PASSWORD)
skip_headers = ["keep-alive", "proxy-connection", "connection", "accept-encoding"]
class pseudofile():
''' SSL Pseudo File Object'''
def __init__(self, sslobj):
self.sslobj = sslobj
self.closed = 0
def read(self, size):
chunks = []
read = 0
while read < size:
data = self.sslobj.read(size-read)
read += len(data)
chunks.append(data)
return ''.join(chunks)
def readline(self):
line = []
while 1:
char = self.sslobj.read(1)
line.append(char)
if char == "\n": return ''.join(line)
def write(self, data):
bytes = len(data)
while bytes > 0:
sent = self.sslobj.write(data)
if sent == bytes:
break # avoid copy
data = data[sent:]
bytes = bytes - sent
# 下面两个方法是 BaseHTTPServer 里会调用到的
def flush(self):
pass
close = flush
def checkip(f):
def new_f(_self):
(ip, port) = _self.client_address
if ip in allow_clients:
f(_self)
else:
_self.send_error(403)
return new_f
class ProxyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
@checkip
def do_GET(self):
content_length = 0
if hasattr(self, "sslhost"): self.raw_requestline = "%s https://%s%s %s\r\n" % (self.command, self.sslhost, self.path
, self.request_version)
h = [self.raw_requestline]
for kv in self.headers.items():
if kv[0] == 'content-length':
content_length = int(kv[1])
if kv[0] in skip_headers: continue
h.append("%s: %s" % kv)
h.append("connection: close")
req = "\r\n".join(h) + "\r\n\r\n"
if content_length:
req += self.rfile.read(content_length)
encreq = desobj.enc(req)
req = urllib2.Request(REMOTEURL, encreq)
f = urllib2.urlopen(req)
text_mode = f.read(1)
response = f.read()
if text_mode == "1":
response = desobj.dec(response)
self.wfile.write(response)
print 'REQUEST:', self.raw_requestline.strip()
#有时候一些看起来是 text/* 的请求也是 binary mode,通常是 304 Not Modified
print 'RESPONSE: %s, %d Bytes' % ('crypted mode' if text_mode == "1" else 'raw mode', len(response))
self.close_connection = 1
@checkip
def do_CONNECT(self):
# print self.raw_requestline
# "CONNECT twitter.com:443 HTTP/1.1"
self.sslhost = self.raw_requestline.split()[1]
self.wfile.write(self.protocol_version + " 200 Connection established\r\n")
self.wfile.write("Proxy-agent: QYB\r\n\r\n")
# TODO 浏览器端会看到一个警告,但是没有办法;避免警告是不对的,必须让使用者认识到现在是中间人模式
try:
import ssl
self.rfile = pseudofile(ssl.wrap_socket(self.connection, KEYFILE, CERTFILE, True))
self.wfile = self.rfile
self.handle_one_request()
except:
print 'ssl error:', self.raw_requestline
self.close_connection = 1
do_PUT = do_GET
do_POST = do_GET
do_HEAD = do_GET
do_DELETE = do_GET
class ThreadingHTTPServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer): pass
httpd = ThreadingHTTPServer(bind_address, ProxyHandler)
httpd.serve_forever()
最新评论
19 小时 49 分钟之前
19 小时 49 分钟之前
19 小时 50 分钟之前
19 小时 50 分钟之前
19 小时 50 分钟之前
19 小时 51 分钟之前
19 小时 51 分钟之前
19 小时 51 分钟之前
19 小时 51 分钟之前
19 小时 51 分钟之前