Proxy update (for the new network subsystem)
This commit is contained in:
parent
75090abaaf
commit
085e335969
|
@ -4,13 +4,13 @@ import asyncore
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
|
from advanceddispatcher import AdvancedDispatcher
|
||||||
|
|
||||||
class Proxy(asyncore.dispatcher):
|
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
|
||||||
# instances should change too
|
# instances should change too
|
||||||
_proxy = ["", 1080]
|
_proxy = ["", 1080]
|
||||||
_auth = None
|
_auth = None
|
||||||
_buf_len = 131072
|
|
||||||
_remote_dns = True
|
_remote_dns = True
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -34,46 +34,17 @@ class Proxy(asyncore.dispatcher):
|
||||||
def __init__(self, address=None):
|
def __init__(self, address=None):
|
||||||
if (not type(address) in (list,tuple)) or (len(address) < 2) or (type(address[0]) != type('')) or (type(address[1]) != int):
|
if (not type(address) in (list,tuple)) or (len(address) < 2) or (type(address[0]) != type('')) or (type(address[1]) != int):
|
||||||
raise
|
raise
|
||||||
asyncore.dispatcher.__init__(self, self.sock)
|
AdvancedDispatcher.__init__(self, self.sock)
|
||||||
self.destination = address
|
self.destination = address
|
||||||
self.read_buf = ""
|
|
||||||
self.write_buf = ""
|
|
||||||
self.stage = "init"
|
|
||||||
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
self.sslSocket.setblocking(0)
|
self.sslSocket.setblocking(0)
|
||||||
self.connect(self.proxy)
|
self.connect(self.proxy)
|
||||||
|
|
||||||
def process(self):
|
|
||||||
try:
|
|
||||||
getattr(self, "state_" + str(self.stage))()
|
|
||||||
except AttributeError:
|
|
||||||
# missing stage
|
|
||||||
raise
|
|
||||||
|
|
||||||
def set_state(self, state):
|
|
||||||
self.state = state
|
|
||||||
self.read_buf = ""
|
|
||||||
|
|
||||||
def writable(self):
|
|
||||||
return len(self.write_buf) > 0
|
|
||||||
|
|
||||||
def readable(self):
|
|
||||||
return len(self.read_buf) < Proxy._buf_len
|
|
||||||
|
|
||||||
def handle_read(self):
|
|
||||||
self.read_buf += self.recv(Proxy._buf_len)
|
|
||||||
self.process()
|
|
||||||
|
|
||||||
def handle_write(self):
|
|
||||||
written = self.send(self.write_buf)
|
|
||||||
self.write_buf = self.write_buf[written:]
|
|
||||||
self.process()
|
|
||||||
|
|
||||||
|
|
||||||
class SOCKS5(Proxy):
|
class SOCKS5(Proxy):
|
||||||
def __init__(self, address=None, sock=None):
|
def __init__(self, address=None, sock=None):
|
||||||
Proxy.__init__(self, address)
|
Proxy.__init__(self, address)
|
||||||
self.state = 0
|
self.state = "init"
|
||||||
|
|
||||||
def handle_connect(self):
|
def handle_connect(self):
|
||||||
self.process()
|
self.process()
|
||||||
|
@ -83,11 +54,11 @@ class SOCKS5(Proxy):
|
||||||
self.write_buf += struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02)
|
self.write_buf += struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02)
|
||||||
else:
|
else:
|
||||||
self.write_buf += struct.pack('BBB', 0x05, 0x01, 0x00)
|
self.write_buf += struct.pack('BBB', 0x05, 0x01, 0x00)
|
||||||
self.set_state("auth_1")
|
self.set_state("auth_1", 0)
|
||||||
|
|
||||||
def state_auth_1(self):
|
def state_auth_1(self):
|
||||||
if len(self.read_buf) < 2:
|
if not self.read_buf_sufficient(2):
|
||||||
return
|
return False
|
||||||
ret = struct.unpack('BB', self.read_buf)
|
ret = struct.unpack('BB', self.read_buf)
|
||||||
self.read_buf = self.read_buf[2:]
|
self.read_buf = self.read_buf[2:]
|
||||||
if ret[0] != 5:
|
if ret[0] != 5:
|
||||||
|
@ -95,13 +66,13 @@ class SOCKS5(Proxy):
|
||||||
raise
|
raise
|
||||||
elif ret[1] == 0:
|
elif ret[1] == 0:
|
||||||
# no auth required
|
# no auth required
|
||||||
self.set_state("auth_done")
|
self.set_state("auth_done", 2)
|
||||||
elif ret[1] == 2:
|
elif ret[1] == 2:
|
||||||
# username/password
|
# username/password
|
||||||
self.write_buf += struct.pack('BB', 1, len(self._auth[0])) + \
|
self.write_buf += 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")
|
self.set_state("auth_1", 2)
|
||||||
else:
|
else:
|
||||||
if ret[1] == 0xff:
|
if ret[1] == 0xff:
|
||||||
# auth error
|
# auth error
|
||||||
|
@ -111,8 +82,8 @@ class SOCKS5(Proxy):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def state_auth_needed(self):
|
def state_auth_needed(self):
|
||||||
if len(self.read_buf) < 2:
|
if not self.read_buf_sufficient(2):
|
||||||
return
|
return False
|
||||||
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
|
||||||
|
@ -121,37 +92,11 @@ class SOCKS5(Proxy):
|
||||||
# auth error
|
# auth error
|
||||||
raise
|
raise
|
||||||
# all ok
|
# all ok
|
||||||
self.set_state = ("auth_done")
|
self.set_state = ("auth_done", 2)
|
||||||
|
|
||||||
|
|
||||||
class SOCKS5Connection(SOCKS5):
|
|
||||||
def __init__(self, address):
|
|
||||||
SOCKS5.__init__(self, address)
|
|
||||||
|
|
||||||
def state_auth_done(self):
|
|
||||||
# Now we can request the actual connection
|
|
||||||
self.write_buf += struct.pack('BBB', 0x05, 0x01, 0x00)
|
|
||||||
# If the given destination address is an IP address, we'll
|
|
||||||
# use the IPv4 address request even if remote resolving was specified.
|
|
||||||
try:
|
|
||||||
ipaddr = socket.inet_aton(self.destination[0])
|
|
||||||
self.write_buf += chr(0x01).encode() + ipaddr
|
|
||||||
except socket.error:
|
|
||||||
# Well it's not an IP number, so it's probably a DNS name.
|
|
||||||
if Proxy._remote_dns:
|
|
||||||
# Resolve remotely
|
|
||||||
ipaddr = None
|
|
||||||
self.write_buf += chr(0x03).encode() + chr(len(self.destination[0])).encode() + self.destination[0]
|
|
||||||
else:
|
|
||||||
# Resolve locally
|
|
||||||
ipaddr = socket.inet_aton(socket.gethostbyname(self.destination[0]))
|
|
||||||
self.write_buf += chr(0x01).encode() + ipaddr
|
|
||||||
self.write_buf += struct.pack(">H", self.destination[1])
|
|
||||||
self.set_state = ("pre_connect")
|
|
||||||
|
|
||||||
def state_pre_connect(self):
|
def state_pre_connect(self):
|
||||||
if len(self.read_buf) < 4:
|
if not self.read_buf_sufficient(4):
|
||||||
return
|
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
|
# general error
|
||||||
|
@ -168,74 +113,78 @@ class SOCKS5Connection(SOCKS5):
|
||||||
raise
|
raise
|
||||||
#raise Socks5Error((9, _socks5errors[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_long")
|
self.set_state("proxy_addr_1", 4)
|
||||||
elif resp[3:4] == chr(0x03).encode():
|
elif self.read_buf[3:4] == chr(0x03).encode():
|
||||||
self.set_state("proxy_addr_short")
|
self.set_state("proxy_addr_2_1", 4)
|
||||||
else:
|
else:
|
||||||
self.close()
|
self.close()
|
||||||
raise GeneralProxyError((1,_generalerrors[1]))
|
raise GeneralProxyError((1,_generalerrors[1]))
|
||||||
boundport = struct.unpack(">H", self.__recvall(2))[0]
|
|
||||||
self.__proxysockname = (boundaddr, boundport)
|
|
||||||
if ipaddr != None:
|
|
||||||
self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
|
|
||||||
else:
|
|
||||||
self.__proxypeername = (destaddr, destport)
|
|
||||||
|
|
||||||
def state_proxy_addr_long(self):
|
def state_proxy_addr_1(self):
|
||||||
if len(self.read_buf) < 4:
|
if not self.read_buf_sufficient(4):
|
||||||
return
|
return False
|
||||||
self.boundaddr = self.read_buf[0:4]
|
self.boundaddr = self.read_buf[0:4]
|
||||||
self.set_state("proxy_port")
|
self.set_state("proxy_port", 4)
|
||||||
|
|
||||||
def state_proxy_addr_short(self):
|
def state_proxy_addr_2_1(self):
|
||||||
if len(self.read_buf) < 1:
|
if not self.read_buf_sufficient(1):
|
||||||
return
|
return False
|
||||||
self.boundaddr = self.read_buf[0:1]
|
self.address_length = ord(self.read_buf[0:1])
|
||||||
self.set_state("proxy_port")
|
self.set_state("proxy_addr_2_2", 1)
|
||||||
|
|
||||||
|
def state_proxy_addr_2_2(self):
|
||||||
|
if not self.read_buf_sufficient(self.address_length):
|
||||||
|
return False
|
||||||
|
self.boundaddr = read_buf
|
||||||
|
self.set_state("proxy_port", self.address_length)
|
||||||
|
|
||||||
def state_proxy_port(self):
|
def state_proxy_port(self):
|
||||||
if len(self.read_buf) < 2:
|
if not self.read_buf_sufficient(2):
|
||||||
return
|
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 ipaddr != None:
|
if self.ipaddr != None:
|
||||||
self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
|
self.__proxypeername = (socket.inet_ntoa(self.ipaddr), self.destination[1])
|
||||||
else:
|
else:
|
||||||
self.__proxypeername = (destaddr, destport)
|
self.__proxypeername = (self.destination[1], destport)
|
||||||
|
|
||||||
|
|
||||||
class SOCKS5Resolver(SOCKS5):
|
class SOCKS5Connection(SOCKS5):
|
||||||
def __init__(self, destpair):
|
def __init__(self, address):
|
||||||
SOCKS5.__init__(self, destpair)
|
SOCKS5.__init__(self, address)
|
||||||
|
|
||||||
def state_auth_done(self):
|
def state_auth_done(self):
|
||||||
# Now we can request the actual connection
|
# Now we can request the actual connection
|
||||||
req = struct.pack('BBB', 0x05, 0xF0, 0x00)
|
self.write_buf += struct.pack('BBB', 0x05, 0x01, 0x00)
|
||||||
req += chr(0x03).encode() + chr(len(host)).encode() + host
|
# If the given destination address is an IP address, we'll
|
||||||
req = req + struct.pack(">H", 8444)
|
# use the IPv4 address request even if remote resolving was specified.
|
||||||
self.sendall(req)
|
try:
|
||||||
# Get the response
|
self.ipaddr = socket.inet_aton(self.destination[0])
|
||||||
ip = ""
|
self.write_buf += chr(0x01).encode() + ipaddr
|
||||||
resp = self.__recvall(4)
|
except socket.error:
|
||||||
if resp[0:1] != chr(0x05).encode():
|
# Well it's not an IP number, so it's probably a DNS name.
|
||||||
self.close()
|
if Proxy._remote_dns:
|
||||||
raise GeneralProxyError((1, _generalerrors[1]))
|
# Resolve remotely
|
||||||
elif resp[1:2] != chr(0x00).encode():
|
self.ipaddr = None
|
||||||
# Connection failed
|
self.write_buf += chr(0x03).encode() + chr(len(self.destination[0])).encode() + self.destination[0]
|
||||||
self.close()
|
|
||||||
if ord(resp[1:2])<=8:
|
|
||||||
raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])]))
|
|
||||||
else:
|
else:
|
||||||
raise Socks5Error((9, _socks5errors[9]))
|
# Resolve locally
|
||||||
# Get the bound address/port
|
self.ipaddr = socket.inet_aton(socket.gethostbyname(self.destination[0]))
|
||||||
elif resp[3:4] == chr(0x01).encode():
|
self.write_buf += chr(0x01).encode() + ipaddr
|
||||||
ip = socket.inet_ntoa(self.__recvall(4))
|
self.write_buf += struct.pack(">H", self.destination[1])
|
||||||
elif resp[3:4] == chr(0x03).encode():
|
self.set_state = ("pre_connect", 0)
|
||||||
resp = resp + self.recv(1)
|
|
||||||
ip = self.__recvall(ord(resp[4:5]))
|
|
||||||
else:
|
class SOCKS5Resolver(SOCKS5):
|
||||||
self.close()
|
def __init__(self, host):
|
||||||
raise GeneralProxyError((1,_generalerrors[1]))
|
self.host = host
|
||||||
boundport = struct.unpack(">H", self.__recvall(2))[0]
|
self.port = 8444
|
||||||
return ip
|
SOCKS5.__init__(self, [self.host, self.port])
|
||||||
|
|
||||||
|
def state_auth_done(self):
|
||||||
|
# Now we can request the actual connection
|
||||||
|
self.write_buf += struct.pack('BBB', 0x05, 0xF0, 0x00)
|
||||||
|
self.write_buf += chr(0x03).encode() + chr(len(self.host)).encode() + self.host
|
||||||
|
self.write_buf += struct.pack(">H", self.port)
|
||||||
|
self.state = "pre_connect"
|
||||||
|
|
Reference in New Issue
Block a user