|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | +""" |
| 3 | + proxy.py |
| 4 | + ~~~~~~~~ |
| 5 | + ⚡⚡⚡ Fast, Lightweight, Pluggable, TLS interception capable proxy server focused on |
| 6 | + Network monitoring, controls & Application development, testing, debugging. |
| 7 | +
|
| 8 | + :copyright: (c) 2013-present by Abhinav Singh and contributors. |
| 9 | + :license: BSD, see LICENSE for more details. |
| 10 | +""" |
| 11 | +import struct |
| 12 | +from typing import Optional |
| 13 | + |
| 14 | + |
| 15 | +NULL = b'\x00' |
| 16 | + |
| 17 | + |
| 18 | +class Socks4Packet: |
| 19 | + """SOCKS4 and SOCKS4a protocol parser. |
| 20 | +
|
| 21 | + FIXME: Currently doesn't buffer during parsing and expects |
| 22 | + packet to arrive within a single socket receive event. |
| 23 | + """ |
| 24 | + |
| 25 | + def __init__(self) -> None: |
| 26 | + # 1 byte, must be equal to 4 |
| 27 | + self.vn: Optional[int] = None |
| 28 | + # 1 byte |
| 29 | + self.cd: Optional[int] = None |
| 30 | + # 2 bytes |
| 31 | + self.dstport: Optional[int] = None |
| 32 | + # 4 bytes |
| 33 | + self.dstip: Optional[bytes] = None |
| 34 | + # Variable bytes, NULL terminated |
| 35 | + self.userid: Optional[bytes] = None |
| 36 | + |
| 37 | + def parse(self, raw: memoryview) -> None: |
| 38 | + cursor = 0 |
| 39 | + # Parse vn |
| 40 | + if self.vn is None: |
| 41 | + assert int(raw[cursor]) == 4 |
| 42 | + self.vn = 4 |
| 43 | + cursor += 1 |
| 44 | + # Parse cd |
| 45 | + self.cd = raw[cursor] |
| 46 | + cursor += 1 |
| 47 | + # Parse dstport |
| 48 | + self.dstport = struct.unpack('!H', raw[cursor:cursor+2])[0] |
| 49 | + cursor += 2 |
| 50 | + # Parse dstip |
| 51 | + self.dstip = struct.unpack('!4s', raw[cursor:cursor+4])[0] |
| 52 | + cursor += 4 |
| 53 | + # Parse userid |
| 54 | + ulen = len(raw) - cursor - 1 |
| 55 | + self.userid = struct.unpack( |
| 56 | + '!%ds' % ulen, raw[cursor:cursor+ulen], |
| 57 | + )[0] |
| 58 | + cursor += ulen |
| 59 | + # Assert null terminated |
| 60 | + assert raw[cursor] == NULL[0] |
| 61 | + |
| 62 | + def pack(self) -> bytes: |
| 63 | + user_id = self.userid or b'' |
| 64 | + return struct.pack( |
| 65 | + '!bbH4s%ds' % len(user_id), |
| 66 | + self.vn, self.cd, |
| 67 | + self.dstport, self.dstip, |
| 68 | + user_id, |
| 69 | + ) + NULL |
0 commit comments