This repository has been archived on 2025-02-22. You can view files and clone it, but cannot push or open issues or pull requests.

168 lines
5.9 KiB
Python
Raw Normal View History

import socket
import struct
from advanceddispatcher import AdvancedDispatcher
import asyncore_pollchoose as asyncore
from proxy import Proxy, ProxyError, GeneralProxyError
class Socks5AuthError(ProxyError): pass
class Socks5Error(ProxyError): pass
class Socks5(Proxy):
def __init__(self, address=None):
Proxy.__init__(self, address)
self.ipaddr = None
self.destport = address[1]
def state_init(self):
if self._auth:
self.writeQueue.put(struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02))
else:
self.writeQueue.put(struct.pack('BBB', 0x05, 0x01, 0x00))
self.set_state("auth_1", 0)
def state_auth_1(self):
if not self.read_buf_sufficient(2):
return False
ret = struct.unpack('BB', self.read_buf)
self.read_buf = self.read_buf[2:]
if ret[0] != 5:
# general error
raise GeneralProxyError
elif ret[1] == 0:
# no auth required
self.set_state("auth_done", 2)
elif ret[1] == 2:
# username/password
self.writeQueue.put(struct.pack('BB', 1, len(self._auth[0])) + \
self._auth[0] + struct.pack('B', len(self._auth[1])) + \
2017-04-16 18:27:15 +02:00
self._auth[1])
self.set_state("auth_1", 2)
else:
if ret[1] == 0xff:
# auth error
raise Socks5AuthError
else:
# other error
raise Socks5Error
def state_auth_needed(self):
if not self.read_buf_sufficient(2):
return False
ret = struct.unpack('BB', self.read_buf)
if ret[0] != 1:
# general error
raise Socks5Error
if ret[1] != 0:
# auth error
raise Socks5AuthError
# all ok
self.set_state = ("auth_done", 2)
def state_pre_connect(self):
if not self.read_buf_sufficient(4):
return False
# Get the response
if self.read_buf[0:1] != chr(0x05).encode():
# general error
self.close()
raise Socks5Error
elif self.read_buf[1:2] != chr(0x00).encode():
# Connection failed
self.close()
if ord(self.read_buf[1:2])<=8:
# socks 5 erro
raise Socks5Error
#raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])]))
else:
raise Socks5Error
#raise Socks5Error((9, _socks5errors[9]))
# Get the bound address/port
elif self.read_buf[3:4] == chr(0x01).encode():
self.set_state("proxy_addr_1", 4)
elif self.read_buf[3:4] == chr(0x03).encode():
self.set_state("proxy_addr_2_1", 4)
else:
self.close()
#raise GeneralProxyError((1,_generalerrors[1]))
raise GeneralProxyError
def state_proxy_addr_1(self):
if not self.read_buf_sufficient(4):
return False
self.boundaddr = self.read_buf[0:4]
self.set_state("proxy_port", 4)
def state_proxy_addr_2_1(self):
if not self.read_buf_sufficient(1):
return False
self.address_length = ord(self.read_buf[0:1])
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):
if not self.read_buf_sufficient(2):
return False
self.boundport = struct.unpack(">H", self.read_buf[0:2])[0]
self.__proxysockname = (self.boundaddr, self.boundport)
if self.ipaddr != None:
self.__proxypeername = (socket.inet_ntoa(self.ipaddr), self.destination[1])
else:
self.__proxypeername = (self.destination[0], self.destport)
self.set_state("socks_handshake_done", 2)
def proxy_sock_name(self):
return socket.inet_ntoa(self.__proxysockname[0])
def state_socks_handshake_done(self):
return False
class Socks5Connection(Socks5):
def __init__(self, address):
Socks5.__init__(self, address=address)
def state_auth_done(self):
# Now we can request the actual connection
self.writeQueue.put(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:
self.ipaddr = socket.inet_aton(self.destination[0])
self.writeQueue.put(chr(0x01).encode() + self.ipaddr)
except socket.error:
# Well it's not an IP number, so it's probably a DNS name.
if Proxy._remote_dns:
# Resolve remotely
self.ipaddr = None
self.writeQueue.put(chr(0x03).encode() + chr(len(self.destination[0])).encode() + self.destination[0])
else:
# Resolve locally
self.ipaddr = socket.inet_aton(socket.gethostbyname(self.destination[0]))
self.writeQueue.put(chr(0x01).encode() + self.ipaddr)
self.writeQueue.put(struct.pack(">H", self.destination[1]))
self.set_state("pre_connect", 0)
class Socks5Resolver(Socks5):
def __init__(self, host):
self.host = host
self.port = 8444
Socks5.__init__(self, address=(self.host, self.port))
def state_auth_done(self):
# Now we can request the actual connection
self.writeQueue.put(struct.pack('BBB', 0x05, 0xF0, 0x00))
self.writeQueue.put(chr(0x03).encode() + chr(len(self.host)).encode() + str(self.host))
self.writeQueue.put(struct.pack(">H", self.port))
self.set_state("pre_connect", 0)
def resolved(self):
print "Resolved %s as %s" % (self.host, self.proxy_sock_name())