Asyncore proxy fixes
- SOCKS5 now seems to work, SOCKS4a untested
This commit is contained in:
parent
916b85c862
commit
189578cba3
|
@ -1,13 +1,36 @@
|
||||||
import socket
|
import socket
|
||||||
|
import time
|
||||||
import state
|
|
||||||
|
|
||||||
from advanceddispatcher import AdvancedDispatcher
|
from advanceddispatcher import AdvancedDispatcher
|
||||||
import asyncore_pollchoose as asyncore
|
import asyncore_pollchoose as asyncore
|
||||||
|
from debug import logger
|
||||||
import network.connectionpool
|
import network.connectionpool
|
||||||
|
import state
|
||||||
|
|
||||||
|
class ProxyError(Exception):
|
||||||
|
errorCodes = ("UnknownError")
|
||||||
|
|
||||||
|
def __init__(self, code):
|
||||||
|
self.code = code
|
||||||
|
try:
|
||||||
|
self.message = self.__class__.errorCodes[self.code]
|
||||||
|
except IndexError:
|
||||||
|
self.message = self.__class__.errorCodes[-1]
|
||||||
|
super(ProxyError, self).__init__(self.message)
|
||||||
|
|
||||||
|
|
||||||
|
class GeneralProxyError(ProxyError):
|
||||||
|
errorCodes = ("Success",
|
||||||
|
"Invalid data",
|
||||||
|
"Not connected",
|
||||||
|
"Not available",
|
||||||
|
"Bad proxy type",
|
||||||
|
"Bad input",
|
||||||
|
"Timed out",
|
||||||
|
"Network unreachable",
|
||||||
|
"Connection refused",
|
||||||
|
"Host unreachable")
|
||||||
|
|
||||||
class ProxyError(Exception): pass
|
|
||||||
class GeneralProxyError(ProxyError): pass
|
|
||||||
|
|
||||||
class Proxy(AdvancedDispatcher):
|
class Proxy(AdvancedDispatcher):
|
||||||
# these are global, and if you change config during runtime, all active/new
|
# these are global, and if you change config during runtime, all active/new
|
||||||
|
@ -22,7 +45,8 @@ class Proxy(AdvancedDispatcher):
|
||||||
|
|
||||||
@proxy.setter
|
@proxy.setter
|
||||||
def proxy(self, address):
|
def proxy(self, address):
|
||||||
if type(address) != tuple or (len(address) < 2) or (type(str(address[0])) != type('')) or (type(address[1]) != int):
|
if not isinstance(address, tuple) or (len(address) < 2) or \
|
||||||
|
(not isinstance(address[0], str) or not isinstance(address[1], int)):
|
||||||
raise ValueError
|
raise ValueError
|
||||||
self.__class__._proxy = address
|
self.__class__._proxy = address
|
||||||
|
|
||||||
|
@ -42,18 +66,17 @@ class Proxy(AdvancedDispatcher):
|
||||||
self.isOutbound = True
|
self.isOutbound = True
|
||||||
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
self.connect(self.proxy)
|
self.connect(self.proxy)
|
||||||
print "connecting in background to %s:%i" % (self.proxy[0], self.proxy[1])
|
|
||||||
|
|
||||||
def handle_connect(self):
|
def handle_connect(self):
|
||||||
|
self.set_state("init")
|
||||||
try:
|
try:
|
||||||
AdvancedDispatcher.handle_connect(self)
|
AdvancedDispatcher.handle_connect(self)
|
||||||
except socket.error as e:
|
except socket.error as e:
|
||||||
if e.errno in asyncore._DISCONNECTED:
|
if e.errno in asyncore._DISCONNECTED:
|
||||||
logger.debug("%s:%i: Connection failed: %s" % (self.destination.host, self.destination.port, str(e)))
|
logger.debug("%s:%i: Connection failed: %s", self.destination.host, self.destination.port, str(e))
|
||||||
return
|
return
|
||||||
|
self.state_init()
|
||||||
|
|
||||||
def state_proxy_handshake_done(self):
|
def state_proxy_handshake_done(self):
|
||||||
self.writeQueue.put(protocol.assembleVersionMessage(self.destination.host, self.destination.port, network.connectionpool.BMConnectionPool().streams, False))
|
|
||||||
self.connectedAt = time.time()
|
self.connectedAt = time.time()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
from advanceddispatcher import AdvancedDispatcher
|
|
||||||
import asyncore_pollchoose as asyncore
|
|
||||||
from proxy import Proxy, ProxyError, GeneralProxyError
|
from proxy import Proxy, ProxyError, GeneralProxyError
|
||||||
|
|
||||||
class Socks4aError(ProxyError): pass
|
class Socks4aError(ProxyError):
|
||||||
|
errorCodes = ("Request granted",
|
||||||
|
"Request rejected or failed",
|
||||||
|
"Request rejected because SOCKS server cannot connect to identd on the client",
|
||||||
|
"Request rejected because the client program and identd report different user-ids",
|
||||||
|
"Unknown error")
|
||||||
|
|
||||||
|
|
||||||
class Socks4a(Proxy):
|
class Socks4a(Proxy):
|
||||||
|
@ -24,22 +27,20 @@ class Socks4a(Proxy):
|
||||||
if self.read_buf[0:1] != chr(0x00).encode():
|
if self.read_buf[0:1] != chr(0x00).encode():
|
||||||
# bad data
|
# bad data
|
||||||
self.close()
|
self.close()
|
||||||
raise Socks4aError
|
raise GeneralProxyError(1)
|
||||||
elif self.read_buf[1:2] != chr(0x5A).encode():
|
elif self.read_buf[1:2] != chr(0x5A).encode():
|
||||||
# Connection failed
|
# Connection failed
|
||||||
self.close()
|
self.close()
|
||||||
if ord(self.read_buf[1:2]) in (91, 92, 93):
|
if ord(self.read_buf[1:2]) in (91, 92, 93):
|
||||||
# socks 4 erro
|
# socks 4 error
|
||||||
raise Socks4aError
|
raise Socks4aError(ord(self.read_buf[1:2]) - 90)
|
||||||
#raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])-90]))
|
|
||||||
else:
|
else:
|
||||||
raise Socks4aError
|
raise Socks4aError(4)
|
||||||
#raise Socks4aError((94, _socks4aerrors[4]))
|
|
||||||
# Get the bound address/port
|
# Get the bound address/port
|
||||||
self.boundport = struct.unpack(">H", self.read_buf[2:4])[0]
|
self.boundport = struct.unpack(">H", self.read_buf[2:4])[0]
|
||||||
self.boundaddr = self.read_buf[4:]
|
self.boundaddr = self.read_buf[4:]
|
||||||
self.__proxysockname = (self.boundaddr, self.boundport)
|
self.__proxysockname = (self.boundaddr, self.boundport)
|
||||||
if self.ipaddr != None:
|
if self.ipaddr:
|
||||||
self.__proxypeername = (socket.inet_ntoa(self.ipaddr), self.destination[1])
|
self.__proxypeername = (socket.inet_ntoa(self.ipaddr), self.destination[1])
|
||||||
else:
|
else:
|
||||||
self.__proxypeername = (self.destination[0], self.destport)
|
self.__proxypeername = (self.destination[0], self.destport)
|
||||||
|
|
|
@ -1,13 +1,27 @@
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
from advanceddispatcher import AdvancedDispatcher
|
|
||||||
import asyncore_pollchoose as asyncore
|
|
||||||
from proxy import Proxy, ProxyError, GeneralProxyError
|
from proxy import Proxy, ProxyError, GeneralProxyError
|
||||||
import network.connectionpool
|
|
||||||
|
|
||||||
class Socks5AuthError(ProxyError): pass
|
class Socks5AuthError(ProxyError):
|
||||||
class Socks5Error(ProxyError): pass
|
errorCodes = ("Succeeded",
|
||||||
|
"Authentication is required",
|
||||||
|
"All offered authentication methods were rejected",
|
||||||
|
"Unknown username or invalid password",
|
||||||
|
"Unknown error")
|
||||||
|
|
||||||
|
|
||||||
|
class Socks5Error(ProxyError):
|
||||||
|
errorCodes = ("Succeeded",
|
||||||
|
"General SOCKS server failure",
|
||||||
|
"Connection not allowed by ruleset",
|
||||||
|
"Network unreachable",
|
||||||
|
"Host unreachable",
|
||||||
|
"Connection refused",
|
||||||
|
"TTL expired",
|
||||||
|
"Command not supported",
|
||||||
|
"Address type not supported",
|
||||||
|
"Unknown error")
|
||||||
|
|
||||||
|
|
||||||
class Socks5(Proxy):
|
class Socks5(Proxy):
|
||||||
|
@ -30,7 +44,7 @@ class Socks5(Proxy):
|
||||||
self.read_buf = self.read_buf[2:]
|
self.read_buf = self.read_buf[2:]
|
||||||
if ret[0] != 5:
|
if ret[0] != 5:
|
||||||
# general error
|
# general error
|
||||||
raise GeneralProxyError
|
raise GeneralProxyError(1)
|
||||||
elif ret[1] == 0:
|
elif ret[1] == 0:
|
||||||
# no auth required
|
# no auth required
|
||||||
self.set_state("auth_done", 2)
|
self.set_state("auth_done", 2)
|
||||||
|
@ -39,14 +53,14 @@ class Socks5(Proxy):
|
||||||
self.writeQueue.put(struct.pack('BB', 1, len(self._auth[0])) + \
|
self.writeQueue.put(struct.pack('BB', 1, len(self._auth[0])) + \
|
||||||
self._auth[0] + struct.pack('B', len(self._auth[1])) + \
|
self._auth[0] + struct.pack('B', len(self._auth[1])) + \
|
||||||
self._auth[1])
|
self._auth[1])
|
||||||
self.set_state("auth_1", 2)
|
self.set_state("auth_needed", 2)
|
||||||
else:
|
else:
|
||||||
if ret[1] == 0xff:
|
if ret[1] == 0xff:
|
||||||
# auth error
|
# auth error
|
||||||
raise Socks5AuthError
|
raise Socks5AuthError(2)
|
||||||
else:
|
else:
|
||||||
# other error
|
# other error
|
||||||
raise Socks5Error
|
raise GeneralProxyError(1)
|
||||||
|
|
||||||
def state_auth_needed(self):
|
def state_auth_needed(self):
|
||||||
if not self.read_buf_sufficient(2):
|
if not self.read_buf_sufficient(2):
|
||||||
|
@ -54,10 +68,10 @@ class Socks5(Proxy):
|
||||||
ret = struct.unpack('BB', self.read_buf)
|
ret = struct.unpack('BB', self.read_buf)
|
||||||
if ret[0] != 1:
|
if ret[0] != 1:
|
||||||
# general error
|
# general error
|
||||||
raise Socks5Error
|
raise GeneralProxyError(1)
|
||||||
if ret[1] != 0:
|
if ret[1] != 0:
|
||||||
# auth error
|
# auth error
|
||||||
raise Socks5AuthError
|
raise Socks5AuthError(3)
|
||||||
# all ok
|
# all ok
|
||||||
self.set_state = ("auth_done", 2)
|
self.set_state = ("auth_done", 2)
|
||||||
|
|
||||||
|
@ -66,19 +80,15 @@ class Socks5(Proxy):
|
||||||
return False
|
return False
|
||||||
# Get the response
|
# Get the response
|
||||||
if self.read_buf[0:1] != chr(0x05).encode():
|
if self.read_buf[0:1] != chr(0x05).encode():
|
||||||
# general error
|
|
||||||
self.close()
|
self.close()
|
||||||
raise Socks5Error
|
raise GeneralProxyError(1)
|
||||||
elif self.read_buf[1:2] != chr(0x00).encode():
|
elif self.read_buf[1:2] != chr(0x00).encode():
|
||||||
# Connection failed
|
# Connection failed
|
||||||
self.close()
|
self.close()
|
||||||
if ord(self.read_buf[1:2])<=8:
|
if ord(self.read_buf[1:2])<=8:
|
||||||
# socks 5 erro
|
raise Socks5Error(ord(self.read_buf[1:2]))
|
||||||
raise Socks5Error
|
|
||||||
#raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])]))
|
|
||||||
else:
|
else:
|
||||||
raise Socks5Error
|
raise Socks5Error(9)
|
||||||
#raise Socks5Error((9, _socks5errors[9]))
|
|
||||||
# Get the bound address/port
|
# Get the bound address/port
|
||||||
elif self.read_buf[3:4] == chr(0x01).encode():
|
elif self.read_buf[3:4] == chr(0x01).encode():
|
||||||
self.set_state("proxy_addr_1", 4)
|
self.set_state("proxy_addr_1", 4)
|
||||||
|
@ -86,8 +96,7 @@ class Socks5(Proxy):
|
||||||
self.set_state("proxy_addr_2_1", 4)
|
self.set_state("proxy_addr_2_1", 4)
|
||||||
else:
|
else:
|
||||||
self.close()
|
self.close()
|
||||||
#raise GeneralProxyError((1,_generalerrors[1]))
|
raise GeneralProxyError(1)
|
||||||
raise GeneralProxyError
|
|
||||||
|
|
||||||
def state_proxy_addr_1(self):
|
def state_proxy_addr_1(self):
|
||||||
if not self.read_buf_sufficient(4):
|
if not self.read_buf_sufficient(4):
|
||||||
|
@ -112,7 +121,7 @@ class Socks5(Proxy):
|
||||||
return False
|
return False
|
||||||
self.boundport = struct.unpack(">H", self.read_buf[0:2])[0]
|
self.boundport = struct.unpack(">H", self.read_buf[0:2])[0]
|
||||||
self.__proxysockname = (self.boundaddr, self.boundport)
|
self.__proxysockname = (self.boundaddr, self.boundport)
|
||||||
if self.ipaddr != None:
|
if self.ipaddr is not None:
|
||||||
self.__proxypeername = (socket.inet_ntoa(self.ipaddr), self.destination[1])
|
self.__proxypeername = (socket.inet_ntoa(self.ipaddr), self.destination[1])
|
||||||
else:
|
else:
|
||||||
self.__proxypeername = (self.destination[0], self.destport)
|
self.__proxypeername = (self.destination[0], self.destport)
|
||||||
|
|
|
@ -181,7 +181,10 @@ class Socks5BMConnection(Socks5Connection, TCPConnection):
|
||||||
TCPConnection.__init__(self, address=address, sock=self.socket)
|
TCPConnection.__init__(self, address=address, sock=self.socket)
|
||||||
self.set_state("init")
|
self.set_state("init")
|
||||||
|
|
||||||
def state_socks_handshake_done(self):
|
def state_proxy_handshake_done(self):
|
||||||
|
Socks5Connection.state_proxy_handshake_done(self)
|
||||||
|
self.writeQueue.put(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \
|
||||||
|
network.connectionpool.BMConnectionPool().streams, False))
|
||||||
self.set_state("bm_header", expectBytes=protocol.Header.size)
|
self.set_state("bm_header", expectBytes=protocol.Header.size)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -192,7 +195,10 @@ class Socks4aBMConnection(Socks4aConnection, TCPConnection):
|
||||||
TCPConnection.__init__(self, address=address, sock=self.socket)
|
TCPConnection.__init__(self, address=address, sock=self.socket)
|
||||||
self.set_state("init")
|
self.set_state("init")
|
||||||
|
|
||||||
def state_socks_handshake_done(self):
|
def state_proxy_handshake_done(self):
|
||||||
|
Socks4aConnection.state_proxy_handshake_done(self)
|
||||||
|
self.writeQueue.put(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \
|
||||||
|
network.connectionpool.BMConnectionPool().streams, False))
|
||||||
self.set_state("bm_header", expectBytes=protocol.Header.size)
|
self.set_state("bm_header", expectBytes=protocol.Header.size)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -216,7 +222,7 @@ class TCPServer(AdvancedDispatcher):
|
||||||
len(network.connectionpool.BMConnectionPool().outboundConnections) > \
|
len(network.connectionpool.BMConnectionPool().outboundConnections) > \
|
||||||
BMConfigParser().safeGetInt("bitmessagesettings", "maxtotalconnections") + \
|
BMConfigParser().safeGetInt("bitmessagesettings", "maxtotalconnections") + \
|
||||||
BMConfigParser().safeGetInt("bitmessagesettings", "maxbootstrapconnections"):
|
BMConfigParser().safeGetInt("bitmessagesettings", "maxbootstrapconnections"):
|
||||||
close(sock)
|
sock.close()
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
network.connectionpool.BMConnectionPool().addConnection(TCPConnection(sock=sock))
|
network.connectionpool.BMConnectionPool().addConnection(TCPConnection(sock=sock))
|
||||||
|
|
Reference in New Issue
Block a user