-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPythonProxy.py
181 lines (160 loc) · 6.24 KB
/
PythonProxy.py
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# -*- coding: cp1252 -*-
# <PythonProxy.py>
#
#Copyright (c) <2009> <Fábio Domingues - fnds3000 in gmail.com>
#
#Permission is hereby granted, free of charge, to any person
#obtaining a copy of this software and associated documentation
#files (the "Software"), to deal in the Software without
#restriction, including without limitation the rights to use,
#copy, modify, merge, publish, distribute, sublicense, and/or sell
#copies of the Software, and to permit persons to whom the
#Software is furnished to do so, subject to the following
#conditions:
#
#The above copyright notice and this permission notice shall be
#included in all copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
#EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
#OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
#HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
#WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
#FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
#OTHER DEALINGS IN THE SOFTWARE.
"""\
Copyright (c) <2009> <Fábio Domingues - fnds3000 in gmail.com> <MIT Licence>
**************************************
*** Python Proxy - A Fast HTTP proxy ***
**************************************
Neste momento este proxy é um Elie Proxy.
Suporta os métodos HTTP:
- OPTIONS;
- GET;
- HEAD;
- POST;
- PUT;
- DELETE;
- TRACE;
- CONENCT.
Suporta:
- Conexões dos cliente em IPv4 ou IPv6;
- Conexões ao alvo em IPv4 e IPv6;
- Conexões todo o tipo de transmissão de dados TCP (CONNECT tunneling),
p.e. ligações SSL, como é o caso do HTTPS.
A fazer:
- Verificar se o input vindo do cliente está correcto;
- Enviar os devidos HTTP erros se não, ou simplesmente quebrar a ligação;
- Criar um gestor de erros;
- Criar ficheiro log de erros;
- Colocar excepções nos sítios onde é previsível a ocorrência de erros,
p.e.sockets e ficheiros;
- Rever tudo e melhorar a estrutura do programar e colocar nomes adequados nas
variáveis e métodos;
- Comentar o programa decentemente;
- Doc Strings.
Funcionalidades futuras:
- Adiconar a funcionalidade de proxy anónimo e transparente;
- Suportar FTP?.
(!) Atenção o que se segue só tem efeito em conexões não CONNECT, para estas o
proxy é sempre Elite.
Qual a diferença entre um proxy Elite, Anónimo e Transparente?
- Um proxy elite é totalmente anónimo, o servidor que o recebe não consegue ter
conhecimento da existência do proxy e não recebe o endereço IP do cliente;
- Quando é usado um proxy anónimo o servidor sabe que o cliente está a usar um
proxy mas não sabe o endereço IP do cliente;
É enviado o cabeçalho HTTP "Proxy-agent".
- Um proxy transparente fornece ao servidor o IP do cliente e um informação que
se está a usar um proxy.
São enviados os cabeçalhos HTTP "Proxy-agent" e "HTTP_X_FORWARDED_FOR".
"""
import socket, thread, select
__version__ = '0.1.0 Draft 1'
BUFLEN = 8192
VERSION = 'Python Proxy/'+__version__
HTTPVER = 'HTTP/1.1'
class ConnectionHandler:
def __init__(self, connection, address, timeout):
self.client = connection
self.client_buffer = ''
self.timeout = timeout
self.method, self.path, self.protocol = self.get_base_header()
if self.method=='CONNECT':
self.method_CONNECT()
elif self.method in ('OPTIONS', 'GET', 'HEAD', 'POST', 'PUT',
'DELETE', 'TRACE'):
self.method_others()
self.client.close()
self.target.close()
def get_base_header(self):
while 1:
self.client_buffer += self.client.recv(BUFLEN)
end = self.client_buffer.find('\n')
if end!=-1:
break
print '%s'%self.client_buffer[:end]#debug
data = (self.client_buffer[:end+1]).split()
self.client_buffer = self.client_buffer[end+1:]
return data
def method_CONNECT(self):
self._connect_target(self.path)
self.client.send(HTTPVER+' 200 Connection established\n'+
'Proxy-agent: %s\n\n'%VERSION)
self.client_buffer = ''
self._read_write()
def method_others(self):
self.path = self.path[7:]
i = self.path.find('/')
host = self.path[:i]
path = self.path[i:]
self._connect_target(host)
self.target.send('%s %s %s\n'%(self.method, path, self.protocol)+
self.client_buffer)
self.client_buffer = ''
self._read_write()
def _connect_target(self, host):
i = host.find(':')
if i!=-1:
port = int(host[i+1:])
host = host[:i]
else:
port = 80
(soc_family, _, _, _, address) = socket.getaddrinfo(host, port)[0]
self.target = socket.socket(soc_family)
self.target.connect(address)
def _read_write(self):
time_out_max = self.timeout/3
socs = [self.client, self.target]
count = 0
while 1:
count += 1
(recv, _, error) = select.select(socs, [], socs, 3)
if error:
break
if recv:
for in_ in recv:
data = in_.recv(BUFLEN)
if in_ is self.client:
out = self.target
else:
out = self.client
if data:
out.send(data)
count = 0
if count == time_out_max:
break
def start_server(host='localhost', port=8080, IPv6=False, timeout=60,
handler=ConnectionHandler):
if IPv6==True:
soc_type=socket.AF_INET6
else:
soc_type=socket.AF_INET
soc = socket.socket(soc_type)
soc.bind((host, port))
print "Serving on %s:%d."%(host, port)#debug
soc.listen(0)
while 1:
thread.start_new_thread(handler, soc.accept()+(timeout,))
if __name__ == '__main__':
start_server()