proxy.py/proxy/socks/packet.py

70 lines
1.9 KiB
Python

# -*- coding: utf-8 -*-
"""
proxy.py
~~~~~~~~
⚡⚡⚡ Fast, Lightweight, Pluggable, TLS interception capable proxy server focused on
Network monitoring, controls & Application development, testing, debugging.
:copyright: (c) 2013-present by Abhinav Singh and contributors.
:license: BSD, see LICENSE for more details.
"""
import struct
from typing import Optional
NULL = b'\x00'
class Socks4Packet:
"""SOCKS4 and SOCKS4a protocol parser.
FIXME: Currently doesn't buffer during parsing and expects
packet to arrive within a single socket receive event.
"""
def __init__(self) -> None:
# 1 byte, must be equal to 4
self.vn: Optional[int] = None
# 1 byte
self.cd: Optional[int] = None
# 2 bytes
self.dstport: Optional[int] = None
# 4 bytes
self.dstip: Optional[bytes] = None
# Variable bytes, NULL terminated
self.userid: Optional[bytes] = None
def parse(self, raw: memoryview) -> None:
cursor = 0
# Parse vn
if self.vn is None:
assert int(raw[cursor]) == 4
self.vn = 4
cursor += 1
# Parse cd
self.cd = raw[cursor]
cursor += 1
# Parse dstport
self.dstport = struct.unpack('!H', raw[cursor:cursor+2])[0]
cursor += 2
# Parse dstip
self.dstip = struct.unpack('!4s', raw[cursor:cursor+4])[0]
cursor += 4
# Parse userid
ulen = len(raw) - cursor - 1
self.userid = struct.unpack(
'!%ds' % ulen, raw[cursor:cursor+ulen],
)[0]
cursor += ulen
# Assert null terminated
assert raw[cursor] == NULL[0]
def pack(self) -> bytes:
user_id = self.userid or b''
return struct.pack(
'!bbH4s%ds' % len(user_id),
self.vn, self.cd,
self.dstport, self.dstip,
user_id,
) + NULL