43
43
import socket
44
44
import struct
45
45
import sys
46
+ import logging
46
47
47
48
PROXY_TYPE_SOCKS4 = 1
48
49
PROXY_TYPE_SOCKS5 = 2
49
50
PROXY_TYPE_HTTP = 3
51
+ PROXY_TYPE_HTTP_NO_TUNNEL = 4
50
52
51
53
_defaultproxy = None
52
54
_orgsocket = socket .socket
@@ -123,6 +125,7 @@ def __init__(self, family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, _soc
123
125
self .__proxy = (None , None , None , None , None , None )
124
126
self .__proxysockname = None
125
127
self .__proxypeername = None
128
+ self .__httptunnel = True
126
129
127
130
def __recvall (self , count ):
128
131
"""__recvall(count) -> data
@@ -136,6 +139,34 @@ def __recvall(self, count):
136
139
data = data + d
137
140
return data
138
141
142
+ def sendall (self , bytes ):
143
+ if 'encode' in dir (bytes ):
144
+ bytes = bytes .encode ()
145
+ if not self .__httptunnel :
146
+ bytes = self .__rewriteproxy (bytes )
147
+ socket .socket .sendall (self , bytes )
148
+
149
+ def __rewriteproxy (self , header ):
150
+ """ rewrite HTTP request headers to support non-tunneling proxies
151
+ (i.e. thos which do not support the CONNECT method).
152
+ This only works for HTTP (not HTTPS) since HTTPS requires tunneling.
153
+ """
154
+ host , endpt = None , None
155
+ hdrs = header .split ("\r \n " )
156
+ for hdr in hdrs :
157
+ if hdr .lower ().startswith ("host:" ):
158
+ host = hdr
159
+ elif hdr .lower ().startswith ("get" ) or hdr .lower ().startswith ("post" ):
160
+ endpt = hdr
161
+ if host and endpt :
162
+ hdrs .remove (host )
163
+ hdrs .remove (endpt )
164
+ host = host .split (" " )[1 ]
165
+ endpt = endpt .split (" " )
166
+ hdrs .insert (0 , "%s http://%s%s %s" % (endpt [0 ], host , endpt [1 ], endpt [2 ]))
167
+ return "\r \n " .join (hdrs )
168
+
169
+
139
170
def setproxy (self , proxytype = None , addr = None , port = None , rdns = True , username = None , password = None ):
140
171
"""setproxy(proxytype, addr[, port[, rdns[, username[, password]]]])
141
172
Sets the proxy to be used.
@@ -376,6 +407,17 @@ def connect(self, destpair):
376
407
portnum = 8080
377
408
_orgsocket .connect (self ,(self .__proxy [1 ], portnum ))
378
409
self .__negotiatehttp (destpair [0 ], destpair [1 ])
410
+ elif self .__proxy [0 ] == PROXY_TYPE_HTTP_NO_TUNNEL :
411
+ if self .__proxy [2 ] != None :
412
+ portnum = self .__proxy [2 ]
413
+ else :
414
+ portnum = 8080
415
+ _orgsocket .connect (self ,(self .__proxy [1 ],portnum ))
416
+ if 443 == destpair [1 ]:
417
+ logging .warn ("SSL connections (generally on port 443) require the use of tunneling - failing back to PROXY_TYPE_HTTP" )
418
+ self .__negotiatehttp (destpair [0 ],destpair [1 ])
419
+ else :
420
+ self .httptunnel = False
379
421
elif self .__proxy [0 ] == None :
380
422
_orgsocket .connect (self , (destpair [0 ], destpair [1 ]))
381
423
else :
0 commit comments