一个几百行代码做出http/https代理服务器的脚本,启动即可做http https透明代理使用
python proxy.py 8992
使用非阻塞io模式,性能还可以。
可以和浏览器一样保持长连接,代码有点乱,不管那么多了能跑就行
几百行代码做出http/https代理服务器代码片段
*1. * [代码] [Python]代码
#!/usr/bin/python #-*- coding:utf-8 -*- import socket, logging import select, errno import os import sys import traceback import gzip from StringIO import StringIO import Queue import threading import time import thread import cgi from cgi import parse_qs import json import imp from os.path import join, getsize import re import ssl ##################user config ################## logger = logging.getLogger("network-server") ############################################# def getTraceStackMsg(): tb = sys.exc_info()[2] msg = '' for i in traceback.format_tb(tb): msg += i return msg def InitLog(): logger.setLevel(logging.DEBUG) fh = logging.FileHandler("network-server.log") fh.setLevel(logging.DEBUG) ch = logging.StreamHandler() ch.setLevel(logging.ERROR) formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") ch.setFormatter(formatter) fh.setFormatter(formatter) logger.addHandler(fh) logger.addHandler(ch) def clearfdpro(epoll_fd, params, fd): try: fd_check = int(fd) except Exception, e: print "fd error" sys.exit(1) try: #print "pid:%s, close fd:%s" % (os.getpid(), fd) epoll_fd.unregister(fd) except Exception, e: #print str(e)+getTraceStackMsg() pass try: param = params[fd] try: addr = param["addr"] if "next" in param: print "close sock, %s:%s" % (addr[0], addr[1]) except Exception, e: pass param["connections"].shutdown(socket.SHUT_RDWR) param["connections"].close() f = param.get("f", None) if f != None: f.close() rc = param.get("rc", None) if rc != None: rc.close() if "read_cache_name" in param: os.remove(param["read_cache_name"]) except Exception, e: #print str(e)+getTraceStackMsg() pass try: del params[fd] #logger.error(getTraceStackMsg()) #logger.error("clear fd:%s" % fd) except Exception, e: #print str(e)+getTraceStackMsg() pass def clearfd(epoll_fd, params, fd): try: param = params[fd] if "nextfd" in param: nextfd = param["nextfd"] next_param = params[nextfd] del param["nextfd"] del next_param["nextfd"] if not "next" in param: #masterfd clearfdpro(epoll_fd, params, nextfd) else: # nextfd if not "writedata" in next_param or len(next_param["writedata"]) == 0: clearfdpro(epoll_fd, params, nextfd) else: next_param["sendandclose"] = "true" clearfdpro(epoll_fd, params, fd) except Exception, e: #print str(e)+getTraceStackMsg() pass def FindHostPort(datas): host_s = -1 host_e = -1 host_str = None host = "" port = "" if not datas.startswith("CONNECT"): host_s = datas.find("Host:") if host_s < 0: host_s = datas.find("host:") if host_s > 0: host_e = datas.find("\r\n", host_s) if host_s > 0 and host_e > 0: host_str = datas[host_s+5:host_e].strip() add_list = host_str.split(":") if len(add_list) == 2: host = add_list[0] port = add_list[1] else: host = add_list[0] port = 80 first_seg = datas.find("\r\n") first_line = datas[0:first_seg] first_line = first_line.replace(" http://%s" % host_str, " ") datas = first_line + datas[first_seg:] else: first_seg = datas.find("\r\n") head_e = datas.find("\r\n\r\n") if first_seg > 0 and head_e > 0: first_line = datas[0:first_seg] 36a0 com,host_str,http_version = re.split('\s+', first_line) add_list = host_str.split(":") if len(add_list) == 2: host = add_list[0] port = add_list[1] else: host = add_list[0] port = 443 host_s = 1 host_e = 1 return host_str,host_s,host_e,host,port,datas def connect_pro(params, param, epoll_fd, datas, fd, cur_time, host, port): try: nextfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) nextfd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) nextfd.settimeout(5) try: nextfd.connect((host, int(port))) except Exception, e: print "########%s,%s connect fail" % (host,port) nextfd.setblocking(0) next_fileno = nextfd.fileno() print "pid:%s, connect %s:%s fd:%s" % (os.getpid(), host, port, next_fileno) if next_fileno in params: print "fileno exist" sys.exit(1) if not datas.startswith("CONNECT"): next_param = {"addr":[host,port],"writelen":0, "connections":nextfd, "time":cur_time, "nextfd":fd} param["nextfd"] = next_fileno next_param["writedata"] = datas next_param["writelen"] = 0 next_param["next"] = "true" param["read_len"] = 0 param["readdata"] = "" params[next_fileno] = next_param epoll_fd.register(next_fileno, select.EPOLLIN | select.EPOLLOUT | select.EPOLLERR | select.EPOLLHUP) epoll_fd.modify(fd, select.EPOLLIN | select.EPOLLERR | select.EPOLLHUP) else: next_param = {"addr":[host,port],"writelen":0, "connections":nextfd, "time":cur_time, "nextfd":fd} param["nextfd"] = next_fileno next_param["next"] = "true" params[next_fileno] = next_param epoll_fd.register(next_fileno, select.EPOLLIN | select.EPOLLERR | select.EPOLLHUP) param["read_len"] = 0 param["readdata"] = "" param["writedata"] = "HTTP/1.1 200 Connection Established\r\nConnection: close\r\n\r\n" param["writelen"] = 0 param["reuse"] = "true" epoll_fd.modify(fd, select.EPOLLIN | select.EPOLLOUT | select.EPOLLERR | select.EPOLLHUP) except socket.error, msg: clearfd(epoll_fd,params,fd) def process_datas(process_status, params, param, epoll_fd, datas, read_len, fd, cur_time): if process_status == "close": clearfd(epoll_fd,params,fd) else: need_connect = False host_str = None host_s = -1 host_e = -1 if "reuse" in param and "next" not in param: if not datas.startswith("CONNECT") and \ not datas.startswith("GET") and \ not datas.startswith("POST") and \ not datas.startswith("PUT"): del param["reuse"] else: host_str,host_s,host_e,host,port,datas = FindHostPort(datas) host_s = int(host_s) host_e = int(host_e) next_fileno = param["nextfd"] next_param = params[next_fileno] addr = next_param["addr"] if host_s > 0 and host_e > 0: if host != addr[0] or str(port) != str(addr[1]): print "%s,%s neq %s,%s" % (host,port,addr[0],addr[1]) need_connect = True del param["nextfd"] del next_param["nextfd"] clearfd(epoll_fd,params,next_fileno) del param["reuse"] else: param["read_len"] = read_len param["readdata"] = datas return None if need_connect or not "nextfd" in param: if host_str == None or not host_s > 0 or not host_e > 0: host_str,host_s,host_e,host,port,datas = FindHostPort(datas) host_s = int(host_s) host_e = int(host_e) if host_s > 0 and host_e > 0: if not datas.startswith("CONNECT"): epoll_fd.modify(fd, select.EPOLLERR | select.EPOLLHUP) # 简单处理,http连接时把读去掉,避免内存攻击 thread.start_new_thread(connect_pro,(params, param, epoll_fd, datas, fd, cur_time, host, port)) else: param["read_len"] = read_len param["readdata"] = datas else: next_fileno = param["nextfd"] next_param = params[next_fileno] if "next" in param: next_param["reuse"] = "true" write_data = next_param.get("writedata", "") write_data += datas next_param["writedata"] = write_data param["read_len"] = 0 param["readdata"] = "" epoll_fd.modify(next_fileno, select.EPOLLIN | select.EPOLLOUT | select.EPOLLERR | select.EPOLLHUP) if process_status == "close_after_process": print "close after process" clearfd(epoll_fd,params,fd) def run_main(listen_fd): try: epoll_fd = select.epoll() epoll_fd.register(listen_fd.fileno(), select.EPOLLIN | select.EPOLLERR | select.EPOLLHUP) print "listen_fd:%s" % listen_fd.fileno() except select.error, msg: logger.error(msg) params = {} last_min_time = -1 while True: epoll_list = epoll_fd.poll() cur_time = time.time() for fd, events in epoll_list: if fd == listen_fd.fileno(): while True: try: conn, addr = listen_fd.accept() conn.setblocking(0) epoll_fd.register(conn.fileno(), select.EPOLLIN | select.EPOLLERR | select.EPOLLHUP) conn.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) #conn.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True) params[conn.fileno()] = {"addr":addr,"writelen":0, "connections":conn, "time":cur_time} except socket.error, msg: break elif select.EPOLLIN & events: param = params.get(fd,None) if param == None: continue param["time"] = cur_time datas = param.get("readdata","") cur_sock = params[fd]["connections"] read_len = param.get("read_len", 0) process_status = "close" while True: try: data = cur_sock.recv(102400) if not data: if datas == "": break else: raise Exception("close after process") else: datas += data read_len += len(data) except socket.error, msg: if msg.errno == errno.EAGAIN: process_status = "process" break else: break except Exception, e: process_status = "close_after_process" break process_datas(process_status, params, param, epoll_fd, datas, read_len, fd, cur_time) elif select.EPOLLHUP & events or select.EPOLLERR & events: clearfd(epoll_fd,params,fd) logger.error("sock: %s error" % fd) elif select.EPOLLOUT & events: param = params.get(fd,None) if param == None: continue param["time"] = cur_time sendLen = param.get("writelen",0) writedata = param.get("writedata", "") total_write_len = len(writedata) cur_sock = param["connections"] f = param.get("f", None) totalsenlen = param.get("totalsenlen", None) if writedata == "": clearfd(epoll_fd,params,fd) continue while True: try: sendLen += cur_sock.send(writedata[sendLen:]) if sendLen == total_write_len: if f != None and totalsenlen != None: readmorelen = 102400 if readmorelen > totalsenlen: readmorelen = totalsenlen morefiledata = "" if readmorelen > 0: morefiledata = f.read(readmorelen) if morefiledata != "": writedata = morefiledata sendLen = 0 total_write_len = len(writedata) totalsenlen -= total_write_len param["writedata"] = writedata param["totalsenlen"] = totalsenlen continue else: f.close() del param["f"] del param["totalsenlen"] if not "sendandclose" in param: param["writedata"] = "" param["writelen"] = 0 epoll_fd.modify(fd, select.EPOLLIN | select.EPOLLERR | select.EPOLLHUP) else: clearfd(epoll_fd,params,fd) break except socket.error, msg: if msg.errno == errno.EAGAIN: param["writelen"] = sendLen break clearfd(epoll_fd,params,fd) break else: continue #check time out if cur_time - last_min_time > 20: last_min_time = cur_time objs = params.items() for (key_fd,value) in objs: fd_time = value.get("time", 0) del_time = cur_time - fd_time if del_time > 20: clearfd(epoll_fd,params,key_fd) elif fd_time < last_min_time: last_min_time = fd_time if __name__ == "__main__": reload(sys) sys.setdefaultencoding('utf8') InitLog() port = int(sys.argv[1]) try: listen_fd = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) except socket.error, msg: logger.error("create socket failed") try: listen_fd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) except socket.error, msg: logger.error("setsocketopt SO_REUSEADDR failed") try: listen_fd.bind(('', port)) except socket.error, msg: logger.error("bind failed") try: listen_fd.listen(10240) listen_fd.setblocking(0) except socket.error, msg: logger.error(msg) child_num = 19 c = 0 while c < child_num: c = c + 1 newpid = os.fork() if newpid == 0: run_main(listen_fd) run_main(listen_fd)
总结
以上所述是小编给大家介绍的Python代码实现http/https代理服务器,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对小牛知识库网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!
本文向大家介绍Python实现简单的代理服务器,包括了Python实现简单的代理服务器的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Python实现简单的代理服务器。分享给大家供大家参考。具体如下: 具备简单的管理功能,运行后 telnet localhost 9000 端口可以进行管理主要功能就是做包转发,如果有一个桥服务器,可以用来外网访问内网用,还是很管用的 希望本文所述对大家的P
这个错误的原因是什么?我如何修复它或设置我想要的代理?
本文向大家介绍python实现简单的TCP代理服务器,包括了python实现简单的TCP代理服务器的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了python实现简单的TCP代理服务器的方法,分享给大家供大家参考。 具体实现代码如下: 完整实例代码点击此处本站下载。 希望本文所述对大家的Python程序设计有所帮助。
本文向大家介绍仅用50行Python代码实现一个简单的代理服务器,包括了仅用50行Python代码实现一个简单的代理服务器的使用技巧和注意事项,需要的朋友参考一下 之前遇到一个场景是这样的: 我在自己的电脑上需要用mongodb图形客户端,但是mongodb的服务器地址没有对外网开放,只能通过先登录主机A,然后再从A连接mongodb服务器B。 本来想通过ssh端口转发的,但是我没有从机器A连接s
ComplexTypeService是一个WebService类,该类的代码如下: import java.io.FileOutputStream; import data.DataForm; public class ComplexTypeService{ // 上传图像,imageByte参数表示上传图像文件的字节, // length参数表示图像文件的字节长度(该参数
我已经编写了一个充当代理服务器的控制台应用程序。现在我也喜欢实现SSL。不喜欢解密任何流量。就像普通的https代理一样。我不知道我应该如何继续。 我应该直接将所有内容写入sslStream吗?浏览器连接如何。我是否也需要包装流,还是可以将所有内容直接写入代理流?我应该使用AuthenticateAsServer并以某种方式从AuthenticateAsServer传递证书吗? IE向我的代理发出