python-socks 2.1.1__py3-none-any.whl → 2.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- python_socks/_version.py +1 -1
- python_socks/async_/anyio/v2/__init__.py +8 -0
- python_socks/async_/anyio/v2/_chain.py +26 -0
- python_socks/async_/anyio/v2/_connect.py +16 -0
- python_socks/async_/anyio/v2/_factory.py +11 -0
- python_socks/async_/anyio/v2/_proxy.py +215 -0
- python_socks/async_/anyio/v2/_stream.py +59 -0
- python_socks/async_/asyncio/v2/_chain.py +14 -19
- python_socks/async_/asyncio/v2/_connect.py +9 -4
- python_socks/async_/asyncio/v2/_proxy.py +103 -85
- python_socks/async_/asyncio/v2/_stream.py +1 -1
- python_socks/async_/trio/v2/_chain.py +14 -19
- python_socks/async_/trio/v2/_connect.py +4 -2
- python_socks/async_/trio/v2/_proxy.py +97 -80
- python_socks/sync/v2/_chain.py +5 -15
- python_socks/sync/v2/_connect.py +19 -0
- python_socks/sync/v2/_proxy.py +71 -64
- {python_socks-2.1.1.dist-info → python_socks-2.3.0.dist-info}/METADATA +1 -1
- {python_socks-2.1.1.dist-info → python_socks-2.3.0.dist-info}/RECORD +22 -15
- {python_socks-2.1.1.dist-info → python_socks-2.3.0.dist-info}/LICENSE.txt +0 -0
- {python_socks-2.1.1.dist-info → python_socks-2.3.0.dist-info}/WHEEL +0 -0
- {python_socks-2.1.1.dist-info → python_socks-2.3.0.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import ssl
|
|
3
|
+
import warnings
|
|
3
4
|
|
|
4
5
|
import async_timeout
|
|
5
6
|
|
|
@@ -21,8 +22,15 @@ class AsyncioProxy:
|
|
|
21
22
|
proxy_host: str,
|
|
22
23
|
proxy_port: int,
|
|
23
24
|
proxy_ssl: ssl.SSLContext = None,
|
|
25
|
+
forward: 'AsyncioProxy' = None,
|
|
24
26
|
loop: asyncio.AbstractEventLoop = None,
|
|
25
27
|
):
|
|
28
|
+
if loop is not None: # pragma: no cover
|
|
29
|
+
warnings.warn(
|
|
30
|
+
'The loop argument is deprecated and scheduled for removal in the future.',
|
|
31
|
+
DeprecationWarning,
|
|
32
|
+
stacklevel=2,
|
|
33
|
+
)
|
|
26
34
|
|
|
27
35
|
if loop is None:
|
|
28
36
|
loop = asyncio.get_event_loop()
|
|
@@ -32,13 +40,8 @@ class AsyncioProxy:
|
|
|
32
40
|
self._proxy_host = proxy_host
|
|
33
41
|
self._proxy_port = proxy_port
|
|
34
42
|
self._proxy_ssl = proxy_ssl
|
|
43
|
+
self._forward = forward
|
|
35
44
|
|
|
36
|
-
self._dest_host = None
|
|
37
|
-
self._dest_port = None
|
|
38
|
-
self._dest_ssl = None
|
|
39
|
-
self._timeout = None
|
|
40
|
-
|
|
41
|
-
self._stream = None
|
|
42
45
|
self._resolver = Resolver(loop=loop)
|
|
43
46
|
|
|
44
47
|
async def connect(
|
|
@@ -47,83 +50,77 @@ class AsyncioProxy:
|
|
|
47
50
|
dest_port: int,
|
|
48
51
|
dest_ssl: ssl.SSLContext = None,
|
|
49
52
|
timeout: float = None,
|
|
50
|
-
_stream: AsyncioSocketStream = None,
|
|
51
53
|
) -> AsyncioSocketStream:
|
|
52
|
-
|
|
53
54
|
if timeout is None:
|
|
54
55
|
timeout = DEFAULT_TIMEOUT
|
|
55
56
|
|
|
56
|
-
self._dest_host = dest_host
|
|
57
|
-
self._dest_port = dest_port
|
|
58
|
-
self._dest_ssl = dest_ssl
|
|
59
|
-
self._timeout = timeout
|
|
60
|
-
|
|
61
57
|
try:
|
|
62
|
-
|
|
58
|
+
async with async_timeout.timeout(timeout):
|
|
59
|
+
return await self._connect(
|
|
60
|
+
dest_host=dest_host,
|
|
61
|
+
dest_port=dest_port,
|
|
62
|
+
dest_ssl=dest_ssl,
|
|
63
|
+
)
|
|
63
64
|
except asyncio.TimeoutError as e:
|
|
64
|
-
raise ProxyTimeoutError('Proxy connection timed out: {}'.format(
|
|
65
|
-
|
|
66
|
-
async def _connect(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
)
|
|
79
|
-
else:
|
|
80
|
-
self._stream = _stream
|
|
81
|
-
|
|
82
|
-
if self._proxy_ssl is not None: # pragma: no cover
|
|
83
|
-
self._stream = await self._stream.start_tls(
|
|
84
|
-
hostname=self._proxy_host,
|
|
85
|
-
ssl_context=self._proxy_ssl,
|
|
86
|
-
)
|
|
87
|
-
except OSError as e:
|
|
88
|
-
await self._close()
|
|
89
|
-
msg = 'Could not connect to proxy {}:{} [{}]'.format(
|
|
90
|
-
self._proxy_host,
|
|
91
|
-
self._proxy_port,
|
|
92
|
-
e.strerror,
|
|
65
|
+
raise ProxyTimeoutError('Proxy connection timed out: {}'.format(timeout)) from e
|
|
66
|
+
|
|
67
|
+
async def _connect(
|
|
68
|
+
self,
|
|
69
|
+
dest_host: str,
|
|
70
|
+
dest_port: int,
|
|
71
|
+
dest_ssl: ssl.SSLContext = None,
|
|
72
|
+
) -> AsyncioSocketStream:
|
|
73
|
+
try:
|
|
74
|
+
if self._forward is None:
|
|
75
|
+
stream = await connect_tcp(
|
|
76
|
+
host=self._proxy_host,
|
|
77
|
+
port=self._proxy_port,
|
|
78
|
+
loop=self._loop,
|
|
93
79
|
)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
)
|
|
107
|
-
except (asyncio.CancelledError, Exception):
|
|
108
|
-
await self._close()
|
|
109
|
-
raise
|
|
110
|
-
|
|
111
|
-
return self._stream
|
|
112
|
-
|
|
113
|
-
async def _negotiate(self):
|
|
114
|
-
raise NotImplementedError()
|
|
80
|
+
else:
|
|
81
|
+
stream = await self._forward.connect(
|
|
82
|
+
dest_host=self._proxy_host,
|
|
83
|
+
dest_port=self._proxy_port,
|
|
84
|
+
)
|
|
85
|
+
except OSError as e:
|
|
86
|
+
raise ProxyConnectionError(
|
|
87
|
+
e.errno,
|
|
88
|
+
f"Couldn't connect to proxy {self._proxy_host}:{self._proxy_port} [{e.strerror}]",
|
|
89
|
+
) from e
|
|
90
|
+
except (asyncio.CancelledError, Exception):
|
|
91
|
+
raise
|
|
115
92
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
93
|
+
try:
|
|
94
|
+
if self._proxy_ssl is not None: # pragma: no cover
|
|
95
|
+
stream = await stream.start_tls(
|
|
96
|
+
hostname=self._proxy_host,
|
|
97
|
+
ssl_context=self._proxy_ssl,
|
|
98
|
+
)
|
|
119
99
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
100
|
+
await self._negotiate(
|
|
101
|
+
stream=stream,
|
|
102
|
+
dest_host=dest_host,
|
|
103
|
+
dest_port=dest_port,
|
|
104
|
+
)
|
|
123
105
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
106
|
+
if dest_ssl is not None:
|
|
107
|
+
stream = await stream.start_tls(
|
|
108
|
+
hostname=dest_host,
|
|
109
|
+
ssl_context=dest_ssl,
|
|
110
|
+
)
|
|
111
|
+
except (asyncio.CancelledError, Exception):
|
|
112
|
+
await stream.close()
|
|
113
|
+
raise
|
|
114
|
+
|
|
115
|
+
return stream
|
|
116
|
+
|
|
117
|
+
async def _negotiate(
|
|
118
|
+
self,
|
|
119
|
+
stream: AsyncioSocketStream,
|
|
120
|
+
dest_host: str,
|
|
121
|
+
dest_port: int,
|
|
122
|
+
):
|
|
123
|
+
raise NotImplementedError()
|
|
127
124
|
|
|
128
125
|
|
|
129
126
|
class Socks5Proxy(AsyncioProxy):
|
|
@@ -135,24 +132,31 @@ class Socks5Proxy(AsyncioProxy):
|
|
|
135
132
|
password=None,
|
|
136
133
|
rdns=None,
|
|
137
134
|
proxy_ssl=None,
|
|
135
|
+
forward: 'AsyncioProxy' = None,
|
|
138
136
|
loop: asyncio.AbstractEventLoop = None,
|
|
139
137
|
):
|
|
140
138
|
super().__init__(
|
|
141
139
|
proxy_host=proxy_host,
|
|
142
140
|
proxy_port=proxy_port,
|
|
143
141
|
proxy_ssl=proxy_ssl,
|
|
142
|
+
forward=forward,
|
|
144
143
|
loop=loop,
|
|
145
144
|
)
|
|
146
145
|
self._username = username
|
|
147
146
|
self._password = password
|
|
148
147
|
self._rdns = rdns
|
|
149
148
|
|
|
150
|
-
async def _negotiate(
|
|
149
|
+
async def _negotiate(
|
|
150
|
+
self,
|
|
151
|
+
stream: AsyncioSocketStream,
|
|
152
|
+
dest_host: str,
|
|
153
|
+
dest_port: int,
|
|
154
|
+
):
|
|
151
155
|
proto = Socks5Proto(
|
|
152
|
-
stream=
|
|
156
|
+
stream=stream,
|
|
153
157
|
resolver=self._resolver,
|
|
154
|
-
dest_host=
|
|
155
|
-
dest_port=
|
|
158
|
+
dest_host=dest_host,
|
|
159
|
+
dest_port=dest_port,
|
|
156
160
|
username=self._username,
|
|
157
161
|
password=self._password,
|
|
158
162
|
rdns=self._rdns,
|
|
@@ -168,23 +172,30 @@ class Socks4Proxy(AsyncioProxy):
|
|
|
168
172
|
user_id=None,
|
|
169
173
|
rdns=None,
|
|
170
174
|
proxy_ssl=None,
|
|
175
|
+
forward: 'AsyncioProxy' = None,
|
|
171
176
|
loop: asyncio.AbstractEventLoop = None,
|
|
172
177
|
):
|
|
173
178
|
super().__init__(
|
|
174
179
|
proxy_host=proxy_host,
|
|
175
180
|
proxy_port=proxy_port,
|
|
176
181
|
proxy_ssl=proxy_ssl,
|
|
182
|
+
forward=forward,
|
|
177
183
|
loop=loop,
|
|
178
184
|
)
|
|
179
185
|
self._user_id = user_id
|
|
180
186
|
self._rdns = rdns
|
|
181
187
|
|
|
182
|
-
async def _negotiate(
|
|
188
|
+
async def _negotiate(
|
|
189
|
+
self,
|
|
190
|
+
stream: AsyncioSocketStream,
|
|
191
|
+
dest_host: str,
|
|
192
|
+
dest_port: int,
|
|
193
|
+
):
|
|
183
194
|
proto = Socks4Proto(
|
|
184
|
-
stream=
|
|
195
|
+
stream=stream,
|
|
185
196
|
resolver=self._resolver,
|
|
186
|
-
dest_host=
|
|
187
|
-
dest_port=
|
|
197
|
+
dest_host=dest_host,
|
|
198
|
+
dest_port=dest_port,
|
|
188
199
|
user_id=self._user_id,
|
|
189
200
|
rdns=self._rdns,
|
|
190
201
|
)
|
|
@@ -199,22 +210,29 @@ class HttpProxy(AsyncioProxy):
|
|
|
199
210
|
username=None,
|
|
200
211
|
password=None,
|
|
201
212
|
proxy_ssl=None,
|
|
213
|
+
forward: 'AsyncioProxy' = None,
|
|
202
214
|
loop: asyncio.AbstractEventLoop = None,
|
|
203
215
|
):
|
|
204
216
|
super().__init__(
|
|
205
217
|
proxy_host=proxy_host,
|
|
206
218
|
proxy_port=proxy_port,
|
|
207
219
|
proxy_ssl=proxy_ssl,
|
|
220
|
+
forward=forward,
|
|
208
221
|
loop=loop,
|
|
209
222
|
)
|
|
210
223
|
self._username = username
|
|
211
224
|
self._password = password
|
|
212
225
|
|
|
213
|
-
async def _negotiate(
|
|
226
|
+
async def _negotiate(
|
|
227
|
+
self,
|
|
228
|
+
stream: AsyncioSocketStream,
|
|
229
|
+
dest_host: str,
|
|
230
|
+
dest_port: int,
|
|
231
|
+
):
|
|
214
232
|
proto = HttpProto(
|
|
215
|
-
stream=
|
|
216
|
-
dest_host=
|
|
217
|
-
dest_port=
|
|
233
|
+
stream=stream,
|
|
234
|
+
dest_host=dest_host,
|
|
235
|
+
dest_port=dest_port,
|
|
218
236
|
username=self._username,
|
|
219
237
|
password=self._password,
|
|
220
238
|
)
|
|
@@ -17,7 +17,7 @@ async def backport_start_tls(
|
|
|
17
17
|
ssl_handshake_timeout=None,
|
|
18
18
|
): # pragma: no cover
|
|
19
19
|
"""
|
|
20
|
-
Python 3.6 asyncio doesn't have a start_tls() method on the loop
|
|
20
|
+
Python 3.6 asyncio doesn't have a start_tls() method on the loop,
|
|
21
21
|
so we use this function in place of the loop's start_tls() method.
|
|
22
22
|
Adapted from this comment:
|
|
23
23
|
https://github.com/urllib3/urllib3/issues/1323#issuecomment-362494839
|
|
@@ -1,31 +1,26 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import Sequence
|
|
2
2
|
from ._proxy import TrioProxy
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class ProxyChain:
|
|
6
|
-
def __init__(self, proxies:
|
|
6
|
+
def __init__(self, proxies: Sequence[TrioProxy]):
|
|
7
7
|
self._proxies = proxies
|
|
8
8
|
|
|
9
|
-
async def connect(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
async def connect(
|
|
10
|
+
self,
|
|
11
|
+
dest_host,
|
|
12
|
+
dest_port,
|
|
13
|
+
dest_ssl=None,
|
|
14
|
+
timeout=None,
|
|
15
|
+
):
|
|
16
|
+
forward = None
|
|
17
|
+
for proxy in self._proxies:
|
|
18
|
+
proxy._forward = forward
|
|
19
|
+
forward = proxy
|
|
13
20
|
|
|
14
|
-
|
|
15
|
-
for i in range(length):
|
|
16
|
-
_stream = await proxies[i].connect(
|
|
17
|
-
dest_host=proxies[i + 1].proxy_host,
|
|
18
|
-
dest_port=proxies[i + 1].proxy_port,
|
|
19
|
-
timeout=timeout,
|
|
20
|
-
_stream=_stream
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
_stream = await proxies[length].connect(
|
|
21
|
+
return await forward.connect(
|
|
24
22
|
dest_host=dest_host,
|
|
25
23
|
dest_port=dest_port,
|
|
26
24
|
dest_ssl=dest_ssl,
|
|
27
25
|
timeout=timeout,
|
|
28
|
-
_stream=_stream
|
|
29
26
|
)
|
|
30
|
-
|
|
31
|
-
return _stream
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
from typing import Optional, Tuple
|
|
2
2
|
|
|
3
3
|
import trio
|
|
4
|
+
from ._stream import TrioSocketStream
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
async def connect_tcp(
|
|
7
8
|
host: str,
|
|
8
9
|
port: int,
|
|
9
10
|
local_addr: Optional[Tuple[str, int]] = None,
|
|
10
|
-
) ->
|
|
11
|
-
|
|
11
|
+
) -> TrioSocketStream:
|
|
12
|
+
trio_stream = await trio.open_tcp_stream(
|
|
12
13
|
host=host,
|
|
13
14
|
port=port,
|
|
14
15
|
local_address=local_addr,
|
|
15
16
|
)
|
|
17
|
+
return TrioSocketStream(trio_stream)
|
|
@@ -2,35 +2,30 @@ import ssl
|
|
|
2
2
|
|
|
3
3
|
import trio
|
|
4
4
|
|
|
5
|
+
from ._connect import connect_tcp
|
|
6
|
+
from ._stream import TrioSocketStream
|
|
7
|
+
from .._resolver import Resolver
|
|
5
8
|
from ...._errors import ProxyConnectionError, ProxyTimeoutError
|
|
6
9
|
from ...._proto.http_async import HttpProto
|
|
7
10
|
from ...._proto.socks4_async import Socks4Proto
|
|
8
11
|
from ...._proto.socks5_async import Socks5Proto
|
|
9
|
-
from .._resolver import Resolver
|
|
10
|
-
from ._stream import TrioSocketStream
|
|
11
|
-
from ._connect import connect_tcp
|
|
12
|
-
from .... import _abc as abc
|
|
13
12
|
|
|
14
13
|
DEFAULT_TIMEOUT = 60
|
|
15
14
|
|
|
16
15
|
|
|
17
|
-
class TrioProxy
|
|
16
|
+
class TrioProxy:
|
|
18
17
|
def __init__(
|
|
19
18
|
self,
|
|
20
19
|
proxy_host: str,
|
|
21
20
|
proxy_port: int,
|
|
22
21
|
proxy_ssl: ssl.SSLContext = None,
|
|
22
|
+
forward: 'TrioProxy' = None,
|
|
23
23
|
):
|
|
24
24
|
self._proxy_host = proxy_host
|
|
25
25
|
self._proxy_port = proxy_port
|
|
26
26
|
self._proxy_ssl = proxy_ssl
|
|
27
|
+
self._forward = forward
|
|
27
28
|
|
|
28
|
-
self._dest_host = None
|
|
29
|
-
self._dest_port = None
|
|
30
|
-
self._dest_ssl = None
|
|
31
|
-
self._timeout = None
|
|
32
|
-
|
|
33
|
-
self._stream = None
|
|
34
29
|
self._resolver = Resolver()
|
|
35
30
|
|
|
36
31
|
async def connect(
|
|
@@ -39,74 +34,75 @@ class TrioProxy(abc.AsyncProxy):
|
|
|
39
34
|
dest_port: int,
|
|
40
35
|
dest_ssl: ssl.SSLContext = None,
|
|
41
36
|
timeout: float = None,
|
|
42
|
-
_stream: TrioSocketStream = None,
|
|
43
37
|
) -> TrioSocketStream:
|
|
44
|
-
|
|
45
38
|
if timeout is None:
|
|
46
39
|
timeout = DEFAULT_TIMEOUT
|
|
47
40
|
|
|
48
|
-
self._dest_host = dest_host
|
|
49
|
-
self._dest_port = dest_port
|
|
50
|
-
self._dest_ssl = dest_ssl
|
|
51
|
-
self._timeout = timeout
|
|
52
|
-
|
|
53
41
|
try:
|
|
54
|
-
with trio.fail_after(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
else:
|
|
63
|
-
self._stream = _stream
|
|
64
|
-
|
|
65
|
-
if self._proxy_ssl is not None:
|
|
66
|
-
self._stream = await self._stream.start_tls(
|
|
67
|
-
hostname=self._proxy_host,
|
|
68
|
-
ssl_context=self._proxy_ssl,
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
await self._negotiate()
|
|
72
|
-
|
|
73
|
-
if self._dest_ssl is not None:
|
|
74
|
-
self._stream = await self._stream.start_tls(
|
|
75
|
-
hostname=self._dest_host,
|
|
76
|
-
ssl_context=self._dest_ssl,
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
return self._stream
|
|
42
|
+
with trio.fail_after(timeout):
|
|
43
|
+
return await self._connect(
|
|
44
|
+
dest_host=dest_host,
|
|
45
|
+
dest_port=dest_port,
|
|
46
|
+
dest_ssl=dest_ssl,
|
|
47
|
+
)
|
|
48
|
+
except trio.TooSlowError as e:
|
|
49
|
+
raise ProxyTimeoutError('Proxy connection timed out: {}'.format(timeout)) from e
|
|
80
50
|
|
|
51
|
+
async def _connect(
|
|
52
|
+
self,
|
|
53
|
+
dest_host: str,
|
|
54
|
+
dest_port: int,
|
|
55
|
+
dest_ssl: ssl.SSLContext = None,
|
|
56
|
+
) -> TrioSocketStream:
|
|
57
|
+
try:
|
|
58
|
+
if self._forward is None:
|
|
59
|
+
stream = await connect_tcp(
|
|
60
|
+
host=self._proxy_host,
|
|
61
|
+
port=self._proxy_port,
|
|
62
|
+
)
|
|
63
|
+
else:
|
|
64
|
+
stream = await self._forward.connect(
|
|
65
|
+
dest_host=self._proxy_host,
|
|
66
|
+
dest_port=self._proxy_port,
|
|
67
|
+
)
|
|
81
68
|
except OSError as e:
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
self._proxy_host,
|
|
85
|
-
|
|
86
|
-
e.strerror,
|
|
87
|
-
)
|
|
88
|
-
raise ProxyConnectionError(e.errno, msg) from e
|
|
89
|
-
except trio.TooSlowError as e:
|
|
90
|
-
await self._close()
|
|
91
|
-
raise ProxyTimeoutError('Proxy connection timed out: {}'.format(self._timeout)) from e
|
|
92
|
-
except Exception:
|
|
93
|
-
await self._close()
|
|
94
|
-
raise
|
|
69
|
+
raise ProxyConnectionError(
|
|
70
|
+
e.errno,
|
|
71
|
+
f"Couldn't connect to proxy {self._proxy_host}:{self._proxy_port} [{e.strerror}]",
|
|
72
|
+
) from e
|
|
95
73
|
|
|
96
|
-
|
|
97
|
-
|
|
74
|
+
try:
|
|
75
|
+
if self._proxy_ssl is not None:
|
|
76
|
+
stream = await stream.start_tls(
|
|
77
|
+
hostname=self._proxy_host,
|
|
78
|
+
ssl_context=self._proxy_ssl,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
await self._negotiate(
|
|
82
|
+
stream=stream,
|
|
83
|
+
dest_host=dest_host,
|
|
84
|
+
dest_port=dest_port,
|
|
85
|
+
)
|
|
98
86
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
87
|
+
if dest_ssl is not None:
|
|
88
|
+
stream = await stream.start_tls(
|
|
89
|
+
hostname=dest_host,
|
|
90
|
+
ssl_context=dest_ssl,
|
|
91
|
+
)
|
|
92
|
+
except BaseException: # trio.Cancelled...
|
|
93
|
+
with trio.CancelScope(shield=True):
|
|
94
|
+
await stream.close()
|
|
95
|
+
raise
|
|
102
96
|
|
|
103
|
-
|
|
104
|
-
def proxy_host(self):
|
|
105
|
-
return self._proxy_host
|
|
97
|
+
return stream
|
|
106
98
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
99
|
+
async def _negotiate(
|
|
100
|
+
self,
|
|
101
|
+
stream: TrioSocketStream,
|
|
102
|
+
dest_host: str,
|
|
103
|
+
dest_port: int,
|
|
104
|
+
):
|
|
105
|
+
raise NotImplementedError
|
|
110
106
|
|
|
111
107
|
|
|
112
108
|
class Socks5Proxy(TrioProxy):
|
|
@@ -118,22 +114,29 @@ class Socks5Proxy(TrioProxy):
|
|
|
118
114
|
password=None,
|
|
119
115
|
rdns=None,
|
|
120
116
|
proxy_ssl=None,
|
|
117
|
+
forward: 'TrioProxy' = None,
|
|
121
118
|
):
|
|
122
119
|
super().__init__(
|
|
123
120
|
proxy_host=proxy_host,
|
|
124
121
|
proxy_port=proxy_port,
|
|
125
122
|
proxy_ssl=proxy_ssl,
|
|
123
|
+
forward=forward,
|
|
126
124
|
)
|
|
127
125
|
self._username = username
|
|
128
126
|
self._password = password
|
|
129
127
|
self._rdns = rdns
|
|
130
128
|
|
|
131
|
-
async def _negotiate(
|
|
129
|
+
async def _negotiate(
|
|
130
|
+
self,
|
|
131
|
+
stream: TrioSocketStream,
|
|
132
|
+
dest_host: str,
|
|
133
|
+
dest_port: int,
|
|
134
|
+
):
|
|
132
135
|
proto = Socks5Proto(
|
|
133
|
-
stream=
|
|
136
|
+
stream=stream,
|
|
134
137
|
resolver=self._resolver,
|
|
135
|
-
dest_host=
|
|
136
|
-
dest_port=
|
|
138
|
+
dest_host=dest_host,
|
|
139
|
+
dest_port=dest_port,
|
|
137
140
|
username=self._username,
|
|
138
141
|
password=self._password,
|
|
139
142
|
rdns=self._rdns,
|
|
@@ -149,21 +152,28 @@ class Socks4Proxy(TrioProxy):
|
|
|
149
152
|
user_id=None,
|
|
150
153
|
rdns=None,
|
|
151
154
|
proxy_ssl=None,
|
|
155
|
+
forward: 'TrioProxy' = None,
|
|
152
156
|
):
|
|
153
157
|
super().__init__(
|
|
154
158
|
proxy_host=proxy_host,
|
|
155
159
|
proxy_port=proxy_port,
|
|
156
160
|
proxy_ssl=proxy_ssl,
|
|
161
|
+
forward=forward,
|
|
157
162
|
)
|
|
158
163
|
self._user_id = user_id
|
|
159
164
|
self._rdns = rdns
|
|
160
165
|
|
|
161
|
-
async def _negotiate(
|
|
166
|
+
async def _negotiate(
|
|
167
|
+
self,
|
|
168
|
+
stream: TrioSocketStream,
|
|
169
|
+
dest_host: str,
|
|
170
|
+
dest_port: int,
|
|
171
|
+
):
|
|
162
172
|
proto = Socks4Proto(
|
|
163
|
-
stream=
|
|
173
|
+
stream=stream,
|
|
164
174
|
resolver=self._resolver,
|
|
165
|
-
dest_host=
|
|
166
|
-
dest_port=
|
|
175
|
+
dest_host=dest_host,
|
|
176
|
+
dest_port=dest_port,
|
|
167
177
|
user_id=self._user_id,
|
|
168
178
|
rdns=self._rdns,
|
|
169
179
|
)
|
|
@@ -178,20 +188,27 @@ class HttpProxy(TrioProxy):
|
|
|
178
188
|
username=None,
|
|
179
189
|
password=None,
|
|
180
190
|
proxy_ssl=None,
|
|
191
|
+
forward: 'TrioProxy' = None,
|
|
181
192
|
):
|
|
182
193
|
super().__init__(
|
|
183
194
|
proxy_host=proxy_host,
|
|
184
195
|
proxy_port=proxy_port,
|
|
185
196
|
proxy_ssl=proxy_ssl,
|
|
197
|
+
forward=forward,
|
|
186
198
|
)
|
|
187
199
|
self._username = username
|
|
188
200
|
self._password = password
|
|
189
201
|
|
|
190
|
-
async def _negotiate(
|
|
202
|
+
async def _negotiate(
|
|
203
|
+
self,
|
|
204
|
+
stream: TrioSocketStream,
|
|
205
|
+
dest_host: str,
|
|
206
|
+
dest_port: int,
|
|
207
|
+
):
|
|
191
208
|
proto = HttpProto(
|
|
192
|
-
stream=
|
|
193
|
-
dest_host=
|
|
194
|
-
dest_port=
|
|
209
|
+
stream=stream,
|
|
210
|
+
dest_host=dest_host,
|
|
211
|
+
dest_port=dest_port,
|
|
195
212
|
username=self._username,
|
|
196
213
|
password=self._password,
|
|
197
214
|
)
|
python_socks/sync/v2/_chain.py
CHANGED
|
@@ -13,24 +13,14 @@ class ProxyChain:
|
|
|
13
13
|
dest_ssl=None,
|
|
14
14
|
timeout=None,
|
|
15
15
|
):
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
forward = None
|
|
17
|
+
for proxy in self._proxies:
|
|
18
|
+
proxy._forward = forward
|
|
19
|
+
forward = proxy
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
for i in range(length):
|
|
21
|
-
stream = proxies[i].connect(
|
|
22
|
-
dest_host=proxies[i + 1].proxy_host,
|
|
23
|
-
dest_port=proxies[i + 1].proxy_port,
|
|
24
|
-
timeout=timeout,
|
|
25
|
-
_stream=stream,
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
stream = proxies[length].connect(
|
|
21
|
+
return forward.connect(
|
|
29
22
|
dest_host=dest_host,
|
|
30
23
|
dest_port=dest_port,
|
|
31
24
|
dest_ssl=dest_ssl,
|
|
32
25
|
timeout=timeout,
|
|
33
|
-
_stream=stream,
|
|
34
26
|
)
|
|
35
|
-
|
|
36
|
-
return stream
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import socket
|
|
2
|
+
from typing import Optional, Tuple
|
|
3
|
+
from ._stream import SyncSocketStream
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def connect_tcp(
|
|
7
|
+
host: str,
|
|
8
|
+
port: int,
|
|
9
|
+
timeout: float = None,
|
|
10
|
+
local_addr: Optional[Tuple[str, int]] = None,
|
|
11
|
+
) -> SyncSocketStream:
|
|
12
|
+
address = (host, port)
|
|
13
|
+
sock = socket.create_connection(
|
|
14
|
+
address,
|
|
15
|
+
timeout,
|
|
16
|
+
source_address=local_addr,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
return SyncSocketStream(sock)
|