Skip to content

Commit e8a2b7c

Browse files
committed
Fix: some socks5 severs expect fully-formed command request
1 parent d5fc12f commit e8a2b7c

File tree

2 files changed

+30
-29
lines changed

2 files changed

+30
-29
lines changed

aiosocks/protocols.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -284,9 +284,9 @@ def socks_request(self, cmd):
284284
yield from self.authenticate()
285285

286286
# build and send command
287-
self.write_request([c.SOCKS_VER5, cmd, c.RSV])
288-
resolved = yield from self.write_address(self._dst_host,
289-
self._dst_port)
287+
dst_addr, resolved = yield from self.build_dst_address(
288+
self._dst_host, self._dst_port)
289+
self.write_request([c.SOCKS_VER5, cmd, c.RSV] + dst_addr)
290290

291291
# read/process command response
292292
resp = yield from self.read_response(3)
@@ -348,7 +348,7 @@ def authenticate(self):
348348
)
349349

350350
@asyncio.coroutine
351-
def write_address(self, host, port):
351+
def build_dst_address(self, host, port):
352352
family_to_byte = {socket.AF_INET: c.SOCKS5_ATYP_IPv4,
353353
socket.AF_INET6: c.SOCKS5_ATYP_IPv6}
354354
port_bytes = struct.pack('>H', port)
@@ -359,8 +359,7 @@ def write_address(self, host, port):
359359
try:
360360
host_bytes = socket.inet_pton(family, host)
361361
req = [family_to_byte[family], host_bytes, port_bytes]
362-
self.write_request(req)
363-
return host, port
362+
return req, (host, port)
364363
except socket.error:
365364
pass
366365

@@ -375,8 +374,7 @@ def write_address(self, host, port):
375374
req = [family_to_byte[family], host_bytes, port_bytes]
376375
host = socket.inet_ntop(family, host_bytes)
377376

378-
self.write_request(req)
379-
return host, port
377+
return req, (host, port)
380378

381379
@asyncio.coroutine
382380
def read_address(self):

tests/test_protocols.py

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ def make_socks5(loop, *, addr=None, auth=None, rr=True, dst=None, r=None,
5353
proxy=addr, proxy_auth=auth, dst=dst, remote_resolve=rr,
5454
loop=loop, app_protocol_factory=ap_factory, waiter=whiter)
5555
proto._stream_writer = mock.Mock()
56+
proto._stream_writer.drain = fake_coroutine(True)
5657

5758
if not isinstance(r, (list, tuple)):
5859
proto.read_response = mock.Mock(
@@ -526,37 +527,40 @@ def test_auth_anonymous_granted(self):
526527
req = proto.authenticate()
527528
self.loop.run_until_complete(req)
528529

529-
def test_wr_addr_ipv4(self):
530+
def test_build_dst_addr_ipv4(self):
530531
proto = make_socks5(self.loop)
531-
req = proto.write_address('127.0.0.1', 80)
532-
self.loop.run_until_complete(req)
532+
c = proto.build_dst_address('127.0.0.1', 80)
533+
dst_req, resolved = self.loop.run_until_complete(c)
533534

534-
proto._stream_writer.write.assert_called_with(
535-
b'\x01\x7f\x00\x00\x01\x00P')
535+
self.assertEqual(dst_req, [0x01, b'\x7f\x00\x00\x01', b'\x00P'])
536+
self.assertEqual(resolved, ('127.0.0.1', 80))
536537

537-
def test_wr_addr_ipv6(self):
538+
def test_build_dst_addr_ipv6(self):
538539
proto = make_socks5(self.loop)
539-
req = proto.write_address(
540+
c = proto.build_dst_address(
540541
'2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d', 80)
541-
self.loop.run_until_complete(req)
542+
dst_req, resolved = self.loop.run_until_complete(c)
542543

543-
proto._stream_writer.write.assert_called_with(
544-
b'\x04 \x01\r\xb8\x11\xa3\t\xd7\x1f4\x8a.\x07\xa0v]\x00P')
544+
self.assertEqual(dst_req, [
545+
0x04, b' \x01\r\xb8\x11\xa3\t\xd7\x1f4\x8a.\x07\xa0v]', b'\x00P'])
546+
self.assertEqual(resolved,
547+
('2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d', 80))
545548

546-
def test_wr_addr_domain_with_remote_resolve(self):
549+
def test_build_dst_addr_domain_with_remote_resolve(self):
547550
proto = make_socks5(self.loop)
548-
req = proto.write_address('python.org', 80)
549-
self.loop.run_until_complete(req)
551+
c = proto.build_dst_address('python.org', 80)
552+
dst_req, resolved = self.loop.run_until_complete(c)
550553

551-
proto._stream_writer.write.assert_called_with(b'\x03\npython.org\x00P')
554+
self.assertEqual(dst_req, [0x03, b'\n', b'python.org', b'\x00P'])
555+
self.assertEqual(resolved, ('python.org', 80))
552556

553-
def test_wr_addr_domain_with_locale_resolve(self):
557+
def test_build_dst_addr_domain_with_locale_resolve(self):
554558
proto = make_socks5(self.loop, rr=False)
555-
req = proto.write_address('python.org', 80)
556-
self.loop.run_until_complete(req)
559+
c = proto.build_dst_address('python.org', 80)
560+
dst_req, resolved = self.loop.run_until_complete(c)
557561

558-
proto._stream_writer.write.assert_called_with(
559-
b'\x01\x7f\x00\x00\x01\x00P')
562+
self.assertEqual(dst_req, [0x01, b'\x7f\x00\x00\x01', b'\x00P'])
563+
self.assertEqual(resolved, ('127.0.0.1', 80))
560564

561565
def test_rd_addr_ipv4(self):
562566
proto = make_socks5(
@@ -624,6 +628,5 @@ def test_socks_req_cmd_granted(self):
624628
self.assertEqual(req.result(), (('python.org', 80), ('127.0.0.1', 80)))
625629
proto._stream_writer.write.assert_has_calls([
626630
mock.call(b'\x05\x02\x00\x02'),
627-
mock.call(b'\x05\x01\x00'),
628-
mock.call(b'\x03\npython.org\x00P')
631+
mock.call(b'\x05\x01\x00\x03\npython.org\x00P')
629632
])

0 commit comments

Comments
 (0)