http proxy
2018-06-11 本文已影响0人
金刚_30bf
有时在内网无法访问外网资源 , 但有些应用如conda pip yum 需要在线更新,本例使用一台有两网卡的机器(同时上内外网)作为代理,为内网提供在线更新服务。 (在内网机器隔离比较严格的场景不推荐使用!)
使用python做简单的http代理, 支持CONNECT 和GET方法, 支持http 和 https 。
import urllib.parse
import socket
import select
from http.server import BaseHTTPRequestHandler, HTTPServer
from socketserver import ThreadingMixIn
import sys
class MyHandler(BaseHTTPRequestHandler):
def do_CONNECT(self):
print('CONNECT:',self.client_address,self.requestline, self.headers)
uri = self.path
print("url:", uri)
host,port = urllib.parse.splittype(uri)
address = (host, port or 443)
try:
targetconn = socket.create_connection(address=address)
except socket.error:
self.send_error(504)
return
self.send_response(200, 'Connection Established')
self.send_header('Connection', 'close')
self.end_headers()
conns = [self.connection, targetconn]
keep_connection = True
while(keep_connection):
keep_connection = False
rlist, wlist, xlist = select.select(conns, [], conns, self.timeout)
if (xlist):
break
for r in rlist:
other = conns[1] if r is conns[0] else conns[0]
data = r.recv(8192)
if (data):
other.sendall(data)
keep_connection = True
targetconn.close()
print("Connect end!========================",self.client_address)
def do_GET(self):
print('GET:',self.client_address,self.requestline, self.headers)
uri = self.path
print("url:", uri)
protocol,rest = urllib.parse.splittype(uri)
print("protocol:", protocol)
host,rest = urllib.parse.splithost(rest)
print("host:", host)
path = rest
print("Path:", path)
if (path is None or len(path) == 0):
path = '/'
host,port = urllib.parse.splitnport(host)
print("host:", host)
port = 80 if port < 0 else port
host_ip = socket.gethostbyname(host)
print(host_ip, port)
# print("headers:", self.headers)
send_data = 'GET ' + path + ' ' + self.protocol_version + '\r\n'
head = ''
for key, val in self.headers.items():
head = head + "%s: %s\r\n" % (key,val)
send_data = send_data + head + '\r\n'
print("send_data:" , send_data)
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect((host_ip,port))
client.send(send_data.encode('utf-8'))
data = bytes()
while True:
tmp = client.recv(8192)
if not tmp:
break
data = data + tmp
client.close()
# print("resData:", data)
print("resData len:", len(data))
self.wfile.write(data)
print('GET end ! =====================',self.client_address)
class MyHttpServer(ThreadingMixIn, HTTPServer):
pass
def main(ip, port):
try:
server = MyHttpServer((ip, port), MyHandler)
print('Welcome to the machine...')
server.serve_forever()
except KeyboardInterrupt:
print('^C received, shutting down server')
server.socket.close()
if __name__ == '__main__':
# main()
if (len(sys.argv) == 3):
for arg in sys.argv:
print(arg)
else:
print("Error, arguments less!")
print("Usage: python httpProxy.py ip port ")
sys.exit()
ip = sys.argv[1]
port = int(sys.argv[2])
print("Starting proxy at ", ip, port )
main(ip,port)
https CONNECT
CONNECT 用于建立通道,后续将使用建立的通道进行通信 。
在收到CONNECT请求时 , 回复客户端 200 , ‘Connection Established’ 。
然后与目标服务器建立连接,CONNECT头中有host和端口(即目标服务器的主机和端口)。
监控与客户端和目标服务器的连接socket ,当有读事件时, 读取之然后发送出去;
客户端--》 proxy --》 目标服务器;
目标服务器 --》 proxy --》 客户端 ;
select 的使用
select.select(读列表, 写列表, 执行列表, timeout)
循环处理准备好的读写执行列表, 执行相应操作。