• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

romis2012 / python-socks / 88

pending completion
88

push

travis-ci-com

romis2012
Read socks5 server bound address

26 of 26 new or added lines in 3 files covered. (100.0%)

1588 of 1596 relevant lines covered (99.5%)

3.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.23
/python_socks/_proto/socks5_sync.py
1
import socket
4✔
2
from ipaddress import IPv4Address, IPv6Address
4✔
3

4
from .socks5 import (
4✔
5
    AuthMethod,
6
    AddressType,
7
    AuthMethodsRequest,
8
    AuthMethodsResponse,
9
    AuthRequest,
10
    AuthResponse,
11
    ConnectRequest,
12
    ConnectResponse,
13
)
14
from .. import _abc as abc
4✔
15
from .._errors import ProxyError
4✔
16

17

18
class Socks5Proto:
4✔
19
    def __init__(
4✔
20
        self,
21
        stream: abc.SyncSocketStream,
22
        resolver: abc.SyncResolver,
23
        dest_host,
24
        dest_port,
25
        username=None,
26
        password=None,
27
        rdns=None,
28
    ):
29
        if rdns is None:
4✔
30
            rdns = True
4✔
31

32
        self._dest_port = dest_port
4✔
33
        self._dest_host = dest_host
4✔
34
        self._username = username
4✔
35
        self._password = password
4✔
36
        self._rdns = rdns
4✔
37

38
        self._stream = stream
4✔
39
        self._resolver = resolver
4✔
40

41
    def negotiate(self):
4✔
42
        self._socks_auth()
4✔
43
        self._socks_connect()
4✔
44

45
    def _socks_auth(self):
4✔
46
        auth_method = self._choose_auth_method()
4✔
47

48
        # authenticate
49
        if auth_method == AuthMethod.USERNAME_PASSWORD:
4✔
50
            req = AuthRequest(username=self._username, password=self._password)
4✔
51

52
            self._stream.write_all(bytes(req))
4✔
53

54
            res = AuthResponse(self._stream.read_exact(2))
4✔
55
            res.validate()
4✔
56

57
    def _choose_auth_method(self) -> AuthMethod:
4✔
58
        req = AuthMethodsRequest(username=self._username, password=self._password)
4✔
59

60
        self._stream.write_all(bytes(req))
4✔
61

62
        res = AuthMethodsResponse(self._stream.read_exact(2))
4✔
63
        res.validate(request=req)
4✔
64
        return res.auth_method
4✔
65

66
    def _socks_connect(self):
4✔
67
        req = ConnectRequest(host=self._dest_host, port=self._dest_port, rdns=self._rdns)
4✔
68

69
        if req.need_resolve:
4✔
70
            _, addr = self._resolver.resolve(req.host, family=socket.AF_UNSPEC)
4✔
71
            req.set_resolved_host(addr)
4✔
72

73
        self._stream.write_all(bytes(req))
4✔
74

75
        res = ConnectResponse(self._stream.read_exact(3))
4✔
76
        res.validate()
4✔
77

78
        # read remaining data (server bound address)
79
        # self._stream.read()
80
        self._read_bound_address()
4✔
81

82
    def _read_bound_address(self):
4✔
83
        addr_type, *_ = self._stream.read_exact(1)
4✔
84
        if addr_type == AddressType.IPV4:
4✔
85
            host = self._stream.read_exact(4)
4✔
86
            host = str(IPv4Address(bytes(host)))
4✔
87
        elif addr_type == AddressType.IPV6:
×
88
            host = self._stream.read_exact(16)
×
89
            host = str(IPv6Address(bytes(host)))
×
90
        elif addr_type == AddressType.DOMAIN:  # pragma: no cover
91
            host_len, *_ = self._stream.read_exact(1)
92
            host = self._stream.read_exact(host_len)
93
            host = host.decode('ascii')
94
        else:  # pragma: no cover
95
            raise ProxyError('Invalid address type: {:#02X}'.format(addr_type))
96

97
        port = self._stream.read_exact(2)
4✔
98
        port = int.from_bytes(port, 'big')
4✔
99

100
        return host, port
4✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc