| 1 | """ |
|---|
| 2 | Ported from: |
|---|
| 3 | SocksiPy - Python SOCKS module. |
|---|
| 4 | Version 1.00 |
|---|
| 5 | |
|---|
| 6 | Copyright 2006 Dan-Haim. All rights reserved. |
|---|
| 7 | |
|---|
| 8 | Redistribution and use in source and binary forms, with or without modification, |
|---|
| 9 | are permitted provided that the following conditions are met: |
|---|
| 10 | 1. Redistributions of source code must retain the above copyright notice, this |
|---|
| 11 | list of conditions and the following disclaimer. |
|---|
| 12 | 2. Redistributions in binary form must reproduce the above copyright notice, |
|---|
| 13 | this list of conditions and the following disclaimer in the documentation |
|---|
| 14 | and/or other materials provided with the distribution. |
|---|
| 15 | 3. Neither the name of Dan Haim nor the names of his contributors may be used |
|---|
| 16 | to endorse or promote products derived from this software without specific |
|---|
| 17 | prior written permission. |
|---|
| 18 | |
|---|
| 19 | THIS SOFTWARE IS PROVIDED BY DAN HAIM "AS IS" AND ANY EXPRESS OR IMPLIED |
|---|
| 20 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
|---|
| 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
|---|
| 22 | EVENT SHALL DAN HAIM OR HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
|---|
| 23 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|---|
| 24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA |
|---|
| 25 | OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
|---|
| 26 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
|---|
| 27 | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMANGE. |
|---|
| 28 | |
|---|
| 29 | |
|---|
| 30 | """ |
|---|
| 31 | |
|---|
| 32 | import socket |
|---|
| 33 | import struct |
|---|
| 34 | from twisted.internet.protocol import Protocol,ClientFactory |
|---|
| 35 | |
|---|
| 36 | PROXY_TYPE_SOCKS4 = 1 |
|---|
| 37 | PROXY_TYPE_SOCKS5 = 2 |
|---|
| 38 | PROXY_TYPE_HTTP = 3 |
|---|
| 39 | |
|---|
| 40 | _defaultproxy = None |
|---|
| 41 | _orgsocket = socket.socket |
|---|
| 42 | |
|---|
| 43 | |
|---|
| 44 | |
|---|
| 45 | class ProxyError(Exception): |
|---|
| 46 | def __init__(self, value): |
|---|
| 47 | self.value = value |
|---|
| 48 | def __str__(self): |
|---|
| 49 | return repr(self.value) |
|---|
| 50 | |
|---|
| 51 | class GeneralProxyError(ProxyError): |
|---|
| 52 | def __init__(self, value): |
|---|
| 53 | self.value = value |
|---|
| 54 | def __str__(self): |
|---|
| 55 | return repr(self.value) |
|---|
| 56 | |
|---|
| 57 | class Socks5AuthError(ProxyError): |
|---|
| 58 | def __init__(self, value): |
|---|
| 59 | self.value = value |
|---|
| 60 | def __str__(self): |
|---|
| 61 | return repr(self.value) |
|---|
| 62 | |
|---|
| 63 | class Socks5Error(ProxyError): |
|---|
| 64 | def __init__(self, value): |
|---|
| 65 | self.value = value |
|---|
| 66 | def __str__(self): |
|---|
| 67 | return repr(self.value) |
|---|
| 68 | |
|---|
| 69 | class Socks4Error(ProxyError): |
|---|
| 70 | def __init__(self, value): |
|---|
| 71 | self.value = value |
|---|
| 72 | def __str__(self): |
|---|
| 73 | return repr(self.value) |
|---|
| 74 | |
|---|
| 75 | class HTTPError(ProxyError): |
|---|
| 76 | def __init__(self, value): |
|---|
| 77 | self.value = value |
|---|
| 78 | def __str__(self): |
|---|
| 79 | return repr(self.value) |
|---|
| 80 | |
|---|
| 81 | _generalerrors = ("success", |
|---|
| 82 | "invalid data", |
|---|
| 83 | "not connected", |
|---|
| 84 | "not available", |
|---|
| 85 | "bad proxy type", |
|---|
| 86 | "bad input") |
|---|
| 87 | |
|---|
| 88 | _socks5errors = ("succeeded", |
|---|
| 89 | "general SOCKS server failure", |
|---|
| 90 | "connection not allowed by ruleset", |
|---|
| 91 | "Network unreachable", |
|---|
| 92 | "Host unreachable", |
|---|
| 93 | "Connection refused", |
|---|
| 94 | "TTL expired", |
|---|
| 95 | "Command not supported", |
|---|
| 96 | "Address type not supported", |
|---|
| 97 | "Unknown error") |
|---|
| 98 | |
|---|
| 99 | _socks5autherrors = ("succeeded", |
|---|
| 100 | "authentication is required", |
|---|
| 101 | "all offered authentication methods were rejected", |
|---|
| 102 | "unknown username or invalid password", |
|---|
| 103 | "unknown error") |
|---|
| 104 | |
|---|
| 105 | _socks4errors = ("request granted", |
|---|
| 106 | "request rejected or failed", |
|---|
| 107 | "request rejected because SOCKS server cannot connect to identd on the client", |
|---|
| 108 | "request rejected because the client program and identd report different user-ids", |
|---|
| 109 | "unknown error") |
|---|
| 110 | |
|---|
| 111 | |
|---|
| 112 | class SOCKSClient(Protocol): |
|---|
| 113 | def __init__(self, destpair,proxyconf): |
|---|
| 114 | self.destpair = destpair |
|---|
| 115 | self.__proxy = proxyconf |
|---|
| 116 | |
|---|
| 117 | def setproxy(self,proxytype=None,addr=None,port=None,rdns=True,username=None,password=None): |
|---|
| 118 | """setproxy(proxytype, addr[, port[, rdns[, username[, password]]]]) |
|---|
| 119 | Sets the proxy to be used. |
|---|
| 120 | proxytype - The type of the proxy to be used. Three types |
|---|
| 121 | are supported: PROXY_TYPE_SOCKS4 (including socks4a), |
|---|
| 122 | PROXY_TYPE_SOCKS5 and PROXY_TYPE_HTTP |
|---|
| 123 | addr - The address of the server (IP or DNS). |
|---|
| 124 | port - The port of the server. Defaults to 1080 for SOCKS |
|---|
| 125 | servers and 8080 for HTTP proxy servers. |
|---|
| 126 | rdns - Should DNS queries be preformed on the remote side |
|---|
| 127 | (rather than the local side). The default is True. |
|---|
| 128 | Note: This has no effect with SOCKS4 servers. |
|---|
| 129 | username - Username to authenticate with to the server. |
|---|
| 130 | The default is no authentication. |
|---|
| 131 | password - Password to authenticate with to the server. |
|---|
| 132 | Only relevant when username is also provided. |
|---|
| 133 | """ |
|---|
| 134 | self.__proxy = (proxytype,addr,port,rdns,username,password) |
|---|
| 135 | |
|---|
| 136 | def __negotiatesocks5(self,destaddr,destport): |
|---|
| 137 | """__negotiatesocks5(self,destaddr,destport) |
|---|
| 138 | Negotiates a connection through a SOCKS5 server. |
|---|
| 139 | """ |
|---|
| 140 | # First we'll send the authentication packages we support. |
|---|
| 141 | if (self.__proxy[4]!=None) and (self.__proxy[5]!=None): |
|---|
| 142 | # The username/password details were supplied to the |
|---|
| 143 | # setproxy method so we support the USERNAME/PASSWORD |
|---|
| 144 | # authentication (in addition to the standard none). |
|---|
| 145 | self.transport.write("\x05\x02\x00\x02") |
|---|
| 146 | else: |
|---|
| 147 | # No username/password were entered, therefore we |
|---|
| 148 | # only support connections with no authentication. |
|---|
| 149 | self.transport.write("\x05\x01\x00") |
|---|
| 150 | # We'll receive the server's response to determine which |
|---|
| 151 | # method was selected |
|---|
| 152 | chosenauth = self.checkbuf(2) |
|---|
| 153 | if not chosenauth: |
|---|
| 154 | self.cocommand = ("MoreBytes",2) |
|---|
| 155 | chosenauth = yield |
|---|
| 156 | self.cocommand = "" |
|---|
| 157 | if chosenauth[0] != "\x05": |
|---|
| 158 | self.transport.loseConnection() |
|---|
| 159 | raise GeneralProxyError((1,_generalerrors[1])) |
|---|
| 160 | # Check the chosen authentication method |
|---|
| 161 | if chosenauth[1] == "\x00": |
|---|
| 162 | pass |
|---|
| 163 | elif chosenauth[1] == "\x02": |
|---|
| 164 | # Okay, we need to perform a basic username/password |
|---|
| 165 | # authentication. |
|---|
| 166 | self.transport.write("\x01" + chr(len(self.__proxy[4])) + self.__proxy[4] + chr(len(self.proxy[5])) + self.__proxy[5]) |
|---|
| 167 | authstat = self.checkbuf(8) |
|---|
| 168 | if not authstat: |
|---|
| 169 | self.cocommand = ("MoreBytes",8) |
|---|
| 170 | authstat = yield |
|---|
| 171 | self.cocommand = "" |
|---|
| 172 | if authstat[0] != "\x01": |
|---|
| 173 | # Bad response |
|---|
| 174 | self.transport.loseConnection() |
|---|
| 175 | raise GeneralProxyError((1,_generalerrors[1])) |
|---|
| 176 | if authstat[1] != "\x00": |
|---|
| 177 | # Authentication failed |
|---|
| 178 | self.transport.loseConnection() |
|---|
| 179 | raise Socks5AuthError,((3,_socks5autherrors[3])) |
|---|
| 180 | # Authentication succeeded |
|---|
| 181 | else: |
|---|
| 182 | # Reaching here is always bad |
|---|
| 183 | self.transport.loseConnection() |
|---|
| 184 | if chosenauth[1] == "\xFF": |
|---|
| 185 | raise Socks5AuthError((2,_socks5autherrors[2])) |
|---|
| 186 | else: |
|---|
| 187 | raise GeneralProxyError((1,_generalerrors[1])) |
|---|
| 188 | # Now we can request the actual connection |
|---|
| 189 | req = "\x05\x01\x00" |
|---|
| 190 | # If the given destination address is an IP address, we'll |
|---|
| 191 | # use the IPv4 address request even if remote resolving was specified. |
|---|
| 192 | try: |
|---|
| 193 | ipaddr = socket.inet_aton(destaddr) |
|---|
| 194 | req = req + "\x01" + ipaddr |
|---|
| 195 | except socket.error: |
|---|
| 196 | # Well it's not an IP number, so it's probably a DNS name. |
|---|
| 197 | if self.__proxy[3]==True: |
|---|
| 198 | # Resolve remotely |
|---|
| 199 | ipaddr = None |
|---|
| 200 | req = req + "\x03" + chr(len(destaddr)) + destaddr |
|---|
| 201 | else: |
|---|
| 202 | # Resolve locally |
|---|
| 203 | ipaddr = socket.inet_aton(socket.gethostbyname(destaddr)) |
|---|
| 204 | req = req + "\x01" + ipaddr |
|---|
| 205 | req = req + struct.pack(">H",destport) |
|---|
| 206 | self.transport.write(req) |
|---|
| 207 | # Get the response |
|---|
| 208 | resp = self.checkbuf(4) |
|---|
| 209 | if not resp: |
|---|
| 210 | self.cocommand = ("MoreBytes",4) |
|---|
| 211 | resp = yield |
|---|
| 212 | self.cocommand = "" |
|---|
| 213 | if resp[0] != "\x05": |
|---|
| 214 | self.transport.loseConnection() |
|---|
| 215 | raise GeneralProxyError((1,_generalerrors[1])) |
|---|
| 216 | elif resp[1] != "\x00": |
|---|
| 217 | # Connection failed |
|---|
| 218 | self.transport.loseConnection() |
|---|
| 219 | if ord(resp[1])<=8: |
|---|
| 220 | raise Socks5Error(ord(resp[1]),_generalerrors[ord(resp[1])]) |
|---|
| 221 | else: |
|---|
| 222 | raise Socks5Error(9,_generalerrors[9]) |
|---|
| 223 | # Get the bound address/port |
|---|
| 224 | elif resp[3] == "\x01": |
|---|
| 225 | boundaddr = self.checkbuf(4) |
|---|
| 226 | if not boundaddr: |
|---|
| 227 | self.cocommand = ("MoreBytes",4) |
|---|
| 228 | boundaddr = yield |
|---|
| 229 | self.cocommand = "" |
|---|
| 230 | elif resp[3] == "\x03": |
|---|
| 231 | resp2 = self.checkbuf(1) |
|---|
| 232 | if not resp2: |
|---|
| 233 | self.cocommand = ("MoreBytes",1) |
|---|
| 234 | resp2 = yield |
|---|
| 235 | self.cocommand = "" |
|---|
| 236 | resp = resp + resp2 |
|---|
| 237 | boundaddr = self.checkbuf(resp[4]) |
|---|
| 238 | if not boundaddr: |
|---|
| 239 | self.cocommand = ("MoreBytes",resp[4]) |
|---|
| 240 | boundaddr = yield |
|---|
| 241 | self.cocommand = "" |
|---|
| 242 | else: |
|---|
| 243 | self.transport.loseConnection() |
|---|
| 244 | raise GeneralProxyError((1,_generalerrors[1])) |
|---|
| 245 | recv = self.checkbuf(2) |
|---|
| 246 | if not recv: |
|---|
| 247 | self.cocommand=("MoreBytes",2) |
|---|
| 248 | recv = yield |
|---|
| 249 | self.cocommand="" |
|---|
| 250 | print "Got the last 2 bytes: ", len(recv) |
|---|
| 251 | boundport = struct.unpack(">H",recv)[0] |
|---|
| 252 | self.__proxysockname = (boundaddr,boundport) |
|---|
| 253 | if ipaddr != None: |
|---|
| 254 | self.__proxypeername = (socket.inet_ntoa(ipaddr),destport) |
|---|
| 255 | else: |
|---|
| 256 | self.__proxypeername = (destaddr,destport) |
|---|
| 257 | self.established = True |
|---|
| 258 | self.connectionEstablished() |
|---|
| 259 | def getproxysockname(self): |
|---|
| 260 | """getsockname() -> address info |
|---|
| 261 | Returns the bound IP address and port number at the proxy. |
|---|
| 262 | """ |
|---|
| 263 | return self.__proxysockname |
|---|
| 264 | |
|---|
| 265 | def getpeername(self): |
|---|
| 266 | """getpeername() -> address info |
|---|
| 267 | Returns the IP address and port number of the destination |
|---|
| 268 | machine (note: getproxypeername returns the proxy) |
|---|
| 269 | """ |
|---|
| 270 | return self.__proxypeername |
|---|
| 271 | |
|---|
| 272 | def checkbuf(self, num=None): |
|---|
| 273 | answer = '' |
|---|
| 274 | if num == None and len(self.buf) > 0: |
|---|
| 275 | answer = self.buf |
|---|
| 276 | self.buf = "" |
|---|
| 277 | elif num and len(self.buf) >= num: |
|---|
| 278 | answer = self.buf[:num] |
|---|
| 279 | self.buf = self.buf[num:] |
|---|
| 280 | return answer |
|---|
| 281 | |
|---|
| 282 | |
|---|
| 283 | def __negotiatesocks4(self,destaddr,destport): |
|---|
| 284 | """__negotiatesocks4(self,destaddr,destport) |
|---|
| 285 | Negotiates a connection through a SOCKS4 server. |
|---|
| 286 | """ |
|---|
| 287 | # Check if the destination address provided is an IP address |
|---|
| 288 | rmtrslv = False |
|---|
| 289 | try: |
|---|
| 290 | ipaddr = socket.inet_aton(destaddr) # make asynchronous |
|---|
| 291 | except socket.error: |
|---|
| 292 | # It's a DNS name. Check where it should be resolved. |
|---|
| 293 | if self.__proxy[3]==True: |
|---|
| 294 | ipaddr = "\x00\x00\x00\x01" |
|---|
| 295 | rmtrslv = True |
|---|
| 296 | else: |
|---|
| 297 | ipaddr = socket.inet_aton(socket.gethostbyname(destaddr)) |
|---|
| 298 | # Construct the request packet |
|---|
| 299 | req = "\x04\x01" + struct.pack(">H",destport) + ipaddr |
|---|
| 300 | # The username parameter is considered userid for SOCKS4 |
|---|
| 301 | if self.__proxy[4] != None: |
|---|
| 302 | req = req + self.__proxy[4] |
|---|
| 303 | req = req + "\x00" |
|---|
| 304 | # DNS name if remote resolving is required |
|---|
| 305 | # NOTE: This is actually an extension to the SOCKS4 protocol |
|---|
| 306 | # called SOCKS4A and may not be supported in all cases. |
|---|
| 307 | if rmtrslv==True: |
|---|
| 308 | req = req + destaddr + "\x00" |
|---|
| 309 | self.transport.write(req) |
|---|
| 310 | # Get the response from the server |
|---|
| 311 | resp = self.checkbuf(8) |
|---|
| 312 | if not resp: |
|---|
| 313 | self.cocommand = ("MoreBytes",8) |
|---|
| 314 | resp = yield |
|---|
| 315 | self.cocommand = "" |
|---|
| 316 | if resp[0] != "\x00": |
|---|
| 317 | # Bad data |
|---|
| 318 | self.transport.loseConnection() |
|---|
| 319 | raise GeneralProxyError((1,_generalerrors[1])) |
|---|
| 320 | if resp[1] != "\x5A": |
|---|
| 321 | # Server returned an error |
|---|
| 322 | self.transport.loseConnection() |
|---|
| 323 | if ord(resp[1]) in (91,92,93): |
|---|
| 324 | self.transport.loseConnection() |
|---|
| 325 | raise Socks4Error((ord(resp[1]),_socks4errors[ord(resp[1])-90])) |
|---|
| 326 | else: |
|---|
| 327 | raise Socks4Error((94,_socks4errors[4])) |
|---|
| 328 | # Get the bound address/port |
|---|
| 329 | self.__proxysockname = (socket.inet_ntoa(resp[4:]),struct.unpack(">H",resp[2:4])[0]) |
|---|
| 330 | if rmtrslv != None: |
|---|
| 331 | self.__proxypeername = (socket.inet_ntoa(ipaddr),destport) |
|---|
| 332 | else: |
|---|
| 333 | self.__proxypeername = (destaddr,destport) |
|---|
| 334 | self.established = True |
|---|
| 335 | self.connectionEstablished() |
|---|
| 336 | |
|---|
| 337 | |
|---|
| 338 | def __negotiatehttp(self,destaddr,destport): |
|---|
| 339 | """__negotiatehttp(self,destaddr,destport) |
|---|
| 340 | Negotiates a connection through an HTTP server. |
|---|
| 341 | """ |
|---|
| 342 | # If we need to resolve locally, we do this now |
|---|
| 343 | if self.__proxy[3] == False: |
|---|
| 344 | addr = socket.gethostbyname(destaddr) # from __future__ import better_asynchronous_way_to_do_this |
|---|
| 345 | else: |
|---|
| 346 | addr = destaddr |
|---|
| 347 | self.transport.write("CONNECT " + addr + ":" + str(destport) + " HTTP/1.1\r\n" + "Host: " + destaddr + "\r\n\r\n") |
|---|
| 348 | # We read the response until we get the string "\r\n\r\n" |
|---|
| 349 | resp = self.checkbuf() |
|---|
| 350 | while resp.find("\r\n\r\n")==-1: |
|---|
| 351 | self.cocommand = "MoreBytes" |
|---|
| 352 | resp2 = yield |
|---|
| 353 | self.cocommand = "" |
|---|
| 354 | resp += resp2 |
|---|
| 355 | # We just need the first line to check if the connection |
|---|
| 356 | # was successful |
|---|
| 357 | statusline = resp.splitlines()[0].split(" ",2) |
|---|
| 358 | if statusline[0] not in ("HTTP/1.0","HTTP/1.1"): |
|---|
| 359 | self.transport.loseConnection() |
|---|
| 360 | raise GeneralProxyError((1,_generalerrors[1])) |
|---|
| 361 | try: |
|---|
| 362 | statuscode = int(statusline[1]) |
|---|
| 363 | except ValueError: |
|---|
| 364 | self.transport.loseConnection() |
|---|
| 365 | raise GeneralProxyError((1,_generalerrors[1])) |
|---|
| 366 | if statuscode != 200: |
|---|
| 367 | self.transport.loseConnection() |
|---|
| 368 | raise HTTPError((statuscode,statusline[2])) |
|---|
| 369 | self.__proxysockname = ("0.0.0.0",0) |
|---|
| 370 | self.__proxypeername = (addr,destport) |
|---|
| 371 | |
|---|
| 372 | self.established = True |
|---|
| 373 | self.connectionEstablished() |
|---|
| 374 | |
|---|
| 375 | def dataReceived(self,data): |
|---|
| 376 | if self.cocommand == "MoreBytes": |
|---|
| 377 | tosend = self.buf + data |
|---|
| 378 | self.buf = "" |
|---|
| 379 | try: |
|---|
| 380 | self.coroutine.send(tosend) |
|---|
| 381 | except: |
|---|
| 382 | pass |
|---|
| 383 | elif type(self.cocommand) == tuple and self.cocommand[0] == "MoreBytes": |
|---|
| 384 | bytesneeded = self.cocommand[1] |
|---|
| 385 | self.buf += data |
|---|
| 386 | if len(self.buf) >= bytesneeded: |
|---|
| 387 | try: |
|---|
| 388 | self.coroutine.send(self.buf[:bytesneeded]) |
|---|
| 389 | except: |
|---|
| 390 | pass |
|---|
| 391 | self.buf = self.buf[bytesneeded:] |
|---|
| 392 | else: |
|---|
| 393 | self.buf += data |
|---|
| 394 | |
|---|
| 395 | def connectionMade(self): |
|---|
| 396 | """ |
|---|
| 397 | Connects to the specified destination through a proxy. |
|---|
| 398 | destpar - A tuple of the IP/DNS address and the port number. |
|---|
| 399 | (identical to socket's connect). |
|---|
| 400 | To select the proxy server use setproxy(). |
|---|
| 401 | """ |
|---|
| 402 | self.buf="" |
|---|
| 403 | self.established = False |
|---|
| 404 | self.cocommand = "" |
|---|
| 405 | # Do a minimal input check first |
|---|
| 406 | if (type(self.destpair) in (list,tuple)==False) or (len(self.destpair)<2) or (type(self.destpair[0])!=str) or (type(self.destpair[1])!=int): |
|---|
| 407 | raise GeneralProxyError((5,_generalerrors[5])) |
|---|
| 408 | if self.__proxy[0] == PROXY_TYPE_SOCKS5: |
|---|
| 409 | if self.__proxy[2] != None: |
|---|
| 410 | portnum = self.__proxy[2] |
|---|
| 411 | else: |
|---|
| 412 | portnum = 1080 |
|---|
| 413 | print "Trying SOCKSv5" |
|---|
| 414 | self.coroutine = self.__negotiatesocks5(self.destpair[0],self.destpair[1]) |
|---|
| 415 | elif self.__proxy[0] == PROXY_TYPE_SOCKS4: |
|---|
| 416 | if self.__proxy[2] != None: |
|---|
| 417 | portnum = self.__proxy[2] |
|---|
| 418 | else: |
|---|
| 419 | portnum = 1080 |
|---|
| 420 | print "Trying SOCKSv4" |
|---|
| 421 | self.coroutine = self.__negotiatesocks4(self.destpair[0],self.destpair[1]) |
|---|
| 422 | elif self.__proxy[0] == PROXY_TYPE_HTTP: |
|---|
| 423 | if self.__proxy[2] != None: |
|---|
| 424 | portnum = self.__proxy[2] |
|---|
| 425 | else: |
|---|
| 426 | portnum = 8080 |
|---|
| 427 | print "Trying HTTP" |
|---|
| 428 | self.coroutine = __negotiatehttp(self.destpair[0],self.destpair[1]) |
|---|
| 429 | else: |
|---|
| 430 | raise GeneralProxyError((4,_generalerrors[4])) |
|---|
| 431 | self.coroutine.next() |
|---|
| 432 | def connectionEstablished(self): |
|---|
| 433 | pass |
|---|
| 434 | class SOCKSClientFactory(ClientFactory): |
|---|
| 435 | def __init__(self, destpair, proxytype=None,addr=None,port=None,rdns=True,username=None,password=None,protocol=None): |
|---|
| 436 | """ |
|---|
| 437 | @type destpair = [list|tuple] |
|---|
| 438 | """ |
|---|
| 439 | self.destpair = destpair |
|---|
| 440 | self.proxyconf = [proxytype,addr,port,rdns,username,password] |
|---|
| 441 | def buildProtocol(self, addr): |
|---|
| 442 | return SOCKSClient(self.destpair,self.proxyconf) |
|---|