1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
import select
import socket
import _thread
BUFF_SIZE = 1024
# get http head data from a connection
def get_post(conn):
res = b''
while True:
res += conn.recv(BUFF_SIZE)
if b'\r\n\r\n' in res:
break
return res
class Proxy:
# init. in_conn: browser-proxy connection, out_conn: proxy-web_server connection
def __init__(self, conn, timeout):
self.in_conn = conn
self.out_conn = None
self.timeout = timeout
self.run()
# main function
def run(self):
action, url, http_ver, req, headers = self.__parse_header()
# https
if action in ["CONNECT"]:
self.in_conn.send(b'HTTP/1.1 200 Connection established\r\nProxy-agent: God Proxy\r\n\r\n')
self.__connect(headers)
# http
else:
self.__connect(headers)
self.out_conn.send(req)
self.event_loop()
# close connection
self.in_conn.close()
self.out_conn.close()
# event loop
def event_loop(self):
count = 0
inputs = [self.in_conn, self.out_conn]
outputs = []
while True:
read_list, _, exception_list = select.select(inputs, outputs, inputs, self.timeout)
count += 1
for future_object in read_list:
# once could read, receive data
data = future_object.recv(1024)
if data:
# read in_conn's data, send to out_conn or out_conn to in_conn
if future_object is self.in_conn:
# print(count, 'out conn', data[:10], '...', data[-10:])
self.out_conn.sendall(data)
else:
# print(count, 'in conn', data[:10], '...', data[-10:])
self.in_conn.sendall(data)
if exception_list:
break
# time out
if count > 100:
break
# parse host from url and setting up out_conn socket
def __connect(self, headers):
host_list = headers['Host'].split(':')
host = host_list[0]
if host_list[-1].isdigit():
port = int(host_list[1])
else:
port = 80
socket_info = socket.getaddrinfo(host, port)[0]
self.out_conn = socket.socket(socket_info[0])
self.out_conn.connect(socket_info[4])
print('WEB SITE: ', host, socket_info[4])
# get headers from in_conn and parse
def __parse_header(self):
req = get_post(self.in_conn)
str_req = req[:req.find(b'\r\n\r\n')].decode('utf8')
headers = {}
lines = str_req.split('\r\n')
for line in lines[1:]:
line = line.split(': ')
headers[line[0]] = line[1]
action, url, http_ver = lines[0].split()
return action, url, http_ver, req, headers
def main():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_address = ('0.0.0.0', 8899)
server.bind(server_address)
server.listen(0)
# 1 connection to 1 thread
while True:
conn, addr = server.accept()
_thread.start_new_thread(Proxy, (conn, 3))
if __name__ == '__main__':
main()
|