fix: 修复代理问题
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
from .._abc import SyncSocketStream, AsyncSocketStream
|
||||
|
||||
|
||||
class SyncConnector:
|
||||
def connect(
|
||||
self,
|
||||
stream: SyncSocketStream,
|
||||
host: str,
|
||||
port: int,
|
||||
):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class AsyncConnector:
|
||||
async def connect(
|
||||
self,
|
||||
stream: AsyncSocketStream,
|
||||
host: str,
|
||||
port: int,
|
||||
):
|
||||
raise NotImplementedError
|
||||
@@ -0,0 +1,40 @@
|
||||
from typing import Optional
|
||||
from .._abc import AsyncResolver
|
||||
from .._types import ProxyType
|
||||
|
||||
from .abc import AsyncConnector
|
||||
from .socks5_async import Socks5AsyncConnector
|
||||
from .socks4_async import Socks4AsyncConnector
|
||||
from .http_async import HttpAsyncConnector
|
||||
|
||||
|
||||
def create_connector(
|
||||
proxy_type: ProxyType,
|
||||
username: Optional[str],
|
||||
password: Optional[str],
|
||||
rdns: Optional[bool],
|
||||
resolver: AsyncResolver,
|
||||
) -> AsyncConnector:
|
||||
if proxy_type == ProxyType.SOCKS4:
|
||||
return Socks4AsyncConnector(
|
||||
user_id=username,
|
||||
rdns=rdns,
|
||||
resolver=resolver,
|
||||
)
|
||||
|
||||
if proxy_type == ProxyType.SOCKS5:
|
||||
return Socks5AsyncConnector(
|
||||
username=username,
|
||||
password=password,
|
||||
rdns=rdns,
|
||||
resolver=resolver,
|
||||
)
|
||||
|
||||
if proxy_type == ProxyType.HTTP:
|
||||
return HttpAsyncConnector(
|
||||
username=username,
|
||||
password=password,
|
||||
resolver=resolver,
|
||||
)
|
||||
|
||||
raise ValueError(f'Invalid proxy type: {proxy_type}')
|
||||
@@ -0,0 +1,40 @@
|
||||
from typing import Optional
|
||||
from .._abc import SyncResolver
|
||||
from .._types import ProxyType
|
||||
|
||||
from .abc import SyncConnector
|
||||
from .socks5_sync import Socks5SyncConnector
|
||||
from .socks4_sync import Socks4SyncConnector
|
||||
from .http_sync import HttpSyncConnector
|
||||
|
||||
|
||||
def create_connector(
|
||||
proxy_type: ProxyType,
|
||||
username: Optional[str],
|
||||
password: Optional[str],
|
||||
rdns: Optional[bool],
|
||||
resolver: SyncResolver,
|
||||
) -> SyncConnector:
|
||||
if proxy_type == ProxyType.SOCKS4:
|
||||
return Socks4SyncConnector(
|
||||
user_id=username,
|
||||
rdns=rdns,
|
||||
resolver=resolver,
|
||||
)
|
||||
|
||||
if proxy_type == ProxyType.SOCKS5:
|
||||
return Socks5SyncConnector(
|
||||
username=username,
|
||||
password=password,
|
||||
rdns=rdns,
|
||||
resolver=resolver,
|
||||
)
|
||||
|
||||
if proxy_type == ProxyType.HTTP:
|
||||
return HttpSyncConnector(
|
||||
username=username,
|
||||
password=password,
|
||||
resolver=resolver,
|
||||
)
|
||||
|
||||
raise ValueError(f'Invalid proxy type: {proxy_type}')
|
||||
@@ -0,0 +1,38 @@
|
||||
from typing import Optional
|
||||
from .._abc import AsyncSocketStream, AsyncResolver
|
||||
from .abc import AsyncConnector
|
||||
|
||||
from .._protocols import http
|
||||
|
||||
|
||||
class HttpAsyncConnector(AsyncConnector):
|
||||
def __init__(
|
||||
self,
|
||||
username: Optional[str],
|
||||
password: Optional[str],
|
||||
resolver: AsyncResolver,
|
||||
):
|
||||
self._username = username
|
||||
self._password = password
|
||||
self._resolver = resolver
|
||||
|
||||
async def connect(
|
||||
self,
|
||||
stream: AsyncSocketStream,
|
||||
host: str,
|
||||
port: int,
|
||||
) -> http.ConnectReply:
|
||||
conn = http.Connection()
|
||||
|
||||
request = http.ConnectRequest(
|
||||
host=host,
|
||||
port=port,
|
||||
username=self._username,
|
||||
password=self._password,
|
||||
)
|
||||
data = conn.send(request)
|
||||
await stream.write_all(data)
|
||||
|
||||
data = await stream.read()
|
||||
reply: http.ConnectReply = conn.receive(data)
|
||||
return reply
|
||||
@@ -0,0 +1,38 @@
|
||||
from typing import Optional
|
||||
from .._abc import SyncSocketStream, SyncResolver
|
||||
from .abc import SyncConnector
|
||||
|
||||
from .._protocols import http
|
||||
|
||||
|
||||
class HttpSyncConnector(SyncConnector):
|
||||
def __init__(
|
||||
self,
|
||||
username: Optional[str],
|
||||
password: Optional[str],
|
||||
resolver: SyncResolver,
|
||||
):
|
||||
self._username = username
|
||||
self._password = password
|
||||
self._resolver = resolver
|
||||
|
||||
def connect(
|
||||
self,
|
||||
stream: SyncSocketStream,
|
||||
host: str,
|
||||
port: int,
|
||||
) -> http.ConnectReply:
|
||||
conn = http.Connection()
|
||||
|
||||
request = http.ConnectRequest(
|
||||
host=host,
|
||||
port=port,
|
||||
username=self._username,
|
||||
password=self._password,
|
||||
)
|
||||
data = conn.send(request)
|
||||
stream.write_all(data)
|
||||
|
||||
data = stream.read()
|
||||
reply: http.ConnectReply = conn.receive(data)
|
||||
return reply
|
||||
@@ -0,0 +1,45 @@
|
||||
import socket
|
||||
from typing import Optional
|
||||
|
||||
from .._abc import AsyncSocketStream, AsyncResolver
|
||||
from .abc import AsyncConnector
|
||||
|
||||
from .._protocols import socks4
|
||||
from .._helpers import is_ip_address
|
||||
|
||||
|
||||
class Socks4AsyncConnector(AsyncConnector):
|
||||
def __init__(
|
||||
self,
|
||||
user_id: Optional[str],
|
||||
rdns: Optional[bool],
|
||||
resolver: AsyncResolver,
|
||||
):
|
||||
if rdns is None:
|
||||
rdns = False
|
||||
|
||||
self._user_id = user_id
|
||||
self._rdns = rdns
|
||||
self._resolver = resolver
|
||||
|
||||
async def connect(
|
||||
self,
|
||||
stream: AsyncSocketStream,
|
||||
host: str,
|
||||
port: int,
|
||||
) -> socks4.ConnectReply:
|
||||
conn = socks4.Connection()
|
||||
|
||||
if not is_ip_address(host) and not self._rdns:
|
||||
_, host = await self._resolver.resolve(
|
||||
host,
|
||||
family=socket.AF_INET,
|
||||
)
|
||||
|
||||
request = socks4.ConnectRequest(host=host, port=port, user_id=self._user_id)
|
||||
data = conn.send(request)
|
||||
await stream.write_all(data)
|
||||
|
||||
data = await stream.read_exact(socks4.ConnectReply.SIZE)
|
||||
reply: socks4.ConnectReply = conn.receive(data)
|
||||
return reply
|
||||
@@ -0,0 +1,45 @@
|
||||
import socket
|
||||
from typing import Optional
|
||||
|
||||
from .._abc import SyncSocketStream, SyncResolver
|
||||
from .abc import SyncConnector
|
||||
|
||||
from .._protocols import socks4
|
||||
from .._helpers import is_ip_address
|
||||
|
||||
|
||||
class Socks4SyncConnector(SyncConnector):
|
||||
def __init__(
|
||||
self,
|
||||
user_id: Optional[str],
|
||||
rdns: Optional[bool],
|
||||
resolver: SyncResolver,
|
||||
):
|
||||
if rdns is None:
|
||||
rdns = False
|
||||
|
||||
self._user_id = user_id
|
||||
self._rdns = rdns
|
||||
self._resolver = resolver
|
||||
|
||||
def connect(
|
||||
self,
|
||||
stream: SyncSocketStream,
|
||||
host: str,
|
||||
port: int,
|
||||
) -> socks4.ConnectReply:
|
||||
conn = socks4.Connection()
|
||||
|
||||
if not is_ip_address(host) and not self._rdns:
|
||||
_, host = self._resolver.resolve(
|
||||
host,
|
||||
family=socket.AF_INET,
|
||||
)
|
||||
|
||||
request = socks4.ConnectRequest(host=host, port=port, user_id=self._user_id)
|
||||
data = conn.send(request)
|
||||
stream.write_all(data)
|
||||
|
||||
data = stream.read_exact(socks4.ConnectReply.SIZE)
|
||||
reply: socks4.ConnectReply = conn.receive(data)
|
||||
return reply
|
||||
@@ -0,0 +1,95 @@
|
||||
import socket
|
||||
from typing import Optional
|
||||
|
||||
from .._abc import AsyncSocketStream, AsyncResolver
|
||||
from .abc import AsyncConnector
|
||||
|
||||
from .._protocols import socks5
|
||||
from .._helpers import is_ip_address
|
||||
|
||||
|
||||
class Socks5AsyncConnector(AsyncConnector):
|
||||
def __init__(
|
||||
self,
|
||||
username: Optional[str],
|
||||
password: Optional[str],
|
||||
rdns: Optional[bool],
|
||||
resolver: AsyncResolver,
|
||||
):
|
||||
if rdns is None:
|
||||
rdns = True
|
||||
|
||||
self._username = username
|
||||
self._password = password
|
||||
self._rdns = rdns
|
||||
self._resolver = resolver
|
||||
|
||||
async def connect(
|
||||
self,
|
||||
stream: AsyncSocketStream,
|
||||
host: str,
|
||||
port: int,
|
||||
) -> socks5.ConnectReply:
|
||||
conn = socks5.Connection()
|
||||
|
||||
# Auth methods
|
||||
request = socks5.AuthMethodsRequest(
|
||||
username=self._username,
|
||||
password=self._password,
|
||||
)
|
||||
data = conn.send(request)
|
||||
await stream.write_all(data)
|
||||
|
||||
data = await stream.read_exact(socks5.AuthMethodReply.SIZE)
|
||||
reply: socks5.AuthMethodReply = conn.receive(data)
|
||||
|
||||
# Authenticate
|
||||
if reply.method == socks5.AuthMethod.USERNAME_PASSWORD:
|
||||
request = socks5.AuthRequest(
|
||||
username=self._username,
|
||||
password=self._password,
|
||||
)
|
||||
data = conn.send(request)
|
||||
await stream.write_all(data)
|
||||
|
||||
data = await stream.read_exact(socks5.AuthReply.SIZE)
|
||||
_: socks5.AuthReply = conn.receive(data)
|
||||
|
||||
# Connect
|
||||
if not is_ip_address(host) and not self._rdns:
|
||||
_, host = await self._resolver.resolve(
|
||||
host,
|
||||
family=socket.AF_UNSPEC,
|
||||
)
|
||||
|
||||
request = socks5.ConnectRequest(host=host, port=port)
|
||||
data = conn.send(request)
|
||||
await stream.write_all(data)
|
||||
|
||||
data = await self._read_reply(stream)
|
||||
reply: socks5.ConnectReply = conn.receive(data)
|
||||
return reply
|
||||
|
||||
# noinspection PyMethodMayBeStatic
|
||||
async def _read_reply(self, stream: AsyncSocketStream) -> bytes:
|
||||
data = await stream.read_exact(3)
|
||||
if data[0] != socks5.SOCKS_VER:
|
||||
return data
|
||||
if data[1] != socks5.ReplyCode.SUCCEEDED:
|
||||
return data
|
||||
if data[2] != socks5.RSV:
|
||||
return data
|
||||
|
||||
data += await stream.read_exact(1)
|
||||
addr_type = data[3]
|
||||
|
||||
if addr_type == socks5.AddressType.IPV4:
|
||||
data += await stream.read_exact(6)
|
||||
elif addr_type == socks5.AddressType.IPV6:
|
||||
data += await stream.read_exact(18)
|
||||
elif addr_type == socks5.AddressType.DOMAIN:
|
||||
data += await stream.read_exact(1)
|
||||
host_len = data[-1]
|
||||
data += await stream.read_exact(host_len + 2)
|
||||
|
||||
return data
|
||||
@@ -0,0 +1,86 @@
|
||||
import socket
|
||||
from typing import Optional
|
||||
|
||||
from .._abc import SyncSocketStream, SyncResolver
|
||||
from .abc import SyncConnector
|
||||
|
||||
from .._protocols import socks5
|
||||
from .._helpers import is_ip_address
|
||||
|
||||
|
||||
class Socks5SyncConnector(SyncConnector):
|
||||
def __init__(
|
||||
self,
|
||||
username: Optional[str],
|
||||
password: Optional[str],
|
||||
rdns: Optional[bool],
|
||||
resolver: SyncResolver,
|
||||
):
|
||||
if rdns is None:
|
||||
rdns = True
|
||||
|
||||
self._username = username
|
||||
self._password = password
|
||||
self._rdns = rdns
|
||||
self._resolver = resolver
|
||||
|
||||
def connect(
|
||||
self,
|
||||
stream: SyncSocketStream,
|
||||
host: str,
|
||||
port: int,
|
||||
) -> socks5.ConnectReply:
|
||||
conn = socks5.Connection()
|
||||
|
||||
# Auth methods
|
||||
request = socks5.AuthMethodsRequest(username=self._username, password=self._password)
|
||||
data = conn.send(request)
|
||||
stream.write_all(data)
|
||||
|
||||
data = stream.read_exact(socks5.AuthMethodReply.SIZE)
|
||||
reply: socks5.AuthMethodReply = conn.receive(data)
|
||||
|
||||
# Authenticate
|
||||
if reply.method == socks5.AuthMethod.USERNAME_PASSWORD:
|
||||
request = socks5.AuthRequest(username=self._username, password=self._password)
|
||||
data = conn.send(request)
|
||||
stream.write_all(data)
|
||||
|
||||
data = stream.read_exact(socks5.AuthReply.SIZE)
|
||||
_: socks5.AuthReply = conn.receive(data)
|
||||
|
||||
# Connect
|
||||
if not is_ip_address(host) and not self._rdns:
|
||||
_, host = self._resolver.resolve(host, family=socket.AF_UNSPEC)
|
||||
|
||||
request = socks5.ConnectRequest(host=host, port=port)
|
||||
data = conn.send(request)
|
||||
stream.write_all(data)
|
||||
|
||||
data = self._read_reply(stream)
|
||||
reply: socks5.ConnectReply = conn.receive(data)
|
||||
return reply
|
||||
|
||||
# noinspection PyMethodMayBeStatic
|
||||
def _read_reply(self, stream: SyncSocketStream) -> bytes:
|
||||
data = stream.read_exact(3)
|
||||
if data[0] != socks5.SOCKS_VER:
|
||||
return data
|
||||
if data[1] != socks5.ReplyCode.SUCCEEDED:
|
||||
return data
|
||||
if data[2] != socks5.RSV:
|
||||
return data
|
||||
|
||||
data += stream.read_exact(1)
|
||||
addr_type = data[3]
|
||||
|
||||
if addr_type == socks5.AddressType.IPV4:
|
||||
data += stream.read_exact(6)
|
||||
elif addr_type == socks5.AddressType.IPV6:
|
||||
data += stream.read_exact(18)
|
||||
elif addr_type == socks5.AddressType.DOMAIN:
|
||||
data += stream.read_exact(1)
|
||||
host_len = data[-1]
|
||||
data += stream.read_exact(host_len + 2)
|
||||
|
||||
return data
|
||||
Reference in New Issue
Block a user