diff options
author | shmel1k <shmel1k@ydb.tech> | 2023-11-26 18:16:14 +0300 |
---|---|---|
committer | shmel1k <shmel1k@ydb.tech> | 2023-11-26 18:43:30 +0300 |
commit | b8cf9e88f4c5c64d9406af533d8948deb050d695 (patch) | |
tree | 218eb61fb3c3b96ec08b4d8cdfef383104a87d63 /contrib/python/Twisted/py2/twisted/protocols/haproxy/_v2parser.py | |
parent | 523f645a83a0ec97a0332dbc3863bb354c92a328 (diff) | |
download | ydb-b8cf9e88f4c5c64d9406af533d8948deb050d695.tar.gz |
add kikimr_configure
Diffstat (limited to 'contrib/python/Twisted/py2/twisted/protocols/haproxy/_v2parser.py')
-rw-r--r-- | contrib/python/Twisted/py2/twisted/protocols/haproxy/_v2parser.py | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/contrib/python/Twisted/py2/twisted/protocols/haproxy/_v2parser.py b/contrib/python/Twisted/py2/twisted/protocols/haproxy/_v2parser.py new file mode 100644 index 0000000000..94c495ffe2 --- /dev/null +++ b/contrib/python/Twisted/py2/twisted/protocols/haproxy/_v2parser.py @@ -0,0 +1,215 @@ +# -*- test-case-name: twisted.protocols.haproxy.test.test_v2parser -*- + +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +IProxyParser implementation for version two of the PROXY protocol. +""" + +import binascii +import struct + +from constantly import Values, ValueConstant + +from zope.interface import implementer +from twisted.internet import address +from twisted.python import compat + +from ._exceptions import ( + convertError, InvalidProxyHeader, InvalidNetworkProtocol, + MissingAddressData +) +from . import _info +from . import _interfaces + +class NetFamily(Values): + """ + Values for the 'family' field. + """ + UNSPEC = ValueConstant(0x00) + INET = ValueConstant(0x10) + INET6 = ValueConstant(0x20) + UNIX = ValueConstant(0x30) + + + +class NetProtocol(Values): + """ + Values for 'protocol' field. + """ + UNSPEC = ValueConstant(0) + STREAM = ValueConstant(1) + DGRAM = ValueConstant(2) + + +_HIGH = 0b11110000 +_LOW = 0b00001111 +_LOCALCOMMAND = 'LOCAL' +_PROXYCOMMAND = 'PROXY' + +@implementer(_interfaces.IProxyParser) +class V2Parser(object): + """ + PROXY protocol version two header parser. + + Version two of the PROXY protocol is a binary format. + """ + + PREFIX = b'\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A' + VERSIONS = [32] + COMMANDS = {0: _LOCALCOMMAND, 1: _PROXYCOMMAND} + ADDRESSFORMATS = { + # TCP4 + 17: '!4s4s2H', + 18: '!4s4s2H', + # TCP6 + 33: '!16s16s2H', + 34: '!16s16s2H', + # UNIX + 49: '!108s108s', + 50: '!108s108s', + } + + def __init__(self): + self.buffer = b'' + + + def feed(self, data): + """ + Consume a chunk of data and attempt to parse it. + + @param data: A bytestring. + @type data: bytes + + @return: A two-tuple containing, in order, a L{_interfaces.IProxyInfo} + and any bytes fed to the parser that followed the end of the + header. Both of these values are None until a complete header is + parsed. + + @raises InvalidProxyHeader: If the bytes fed to the parser create an + invalid PROXY header. + """ + self.buffer += data + if len(self.buffer) < 16: + raise InvalidProxyHeader() + + size = struct.unpack('!H', self.buffer[14:16])[0] + 16 + if len(self.buffer) < size: + return (None, None) + + header, remaining = self.buffer[:size], self.buffer[size:] + self.buffer = b'' + info = self.parse(header) + return (info, remaining) + + + @staticmethod + def _bytesToIPv4(bytestring): + """ + Convert packed 32-bit IPv4 address bytes into a dotted-quad ASCII bytes + representation of that address. + + @param bytestring: 4 octets representing an IPv4 address. + @type bytestring: L{bytes} + + @return: a dotted-quad notation IPv4 address. + @rtype: L{bytes} + """ + return b'.'.join( + ('%i' % (ord(b),)).encode('ascii') + for b in compat.iterbytes(bytestring) + ) + + + @staticmethod + def _bytesToIPv6(bytestring): + """ + Convert packed 128-bit IPv6 address bytes into a colon-separated ASCII + bytes representation of that address. + + @param bytestring: 16 octets representing an IPv6 address. + @type bytestring: L{bytes} + + @return: a dotted-quad notation IPv6 address. + @rtype: L{bytes} + """ + hexString = binascii.b2a_hex(bytestring) + return b':'.join( + ('%x' % (int(hexString[b:b+4], 16),)).encode('ascii') + for b in range(0, 32, 4) + ) + + + @classmethod + def parse(cls, line): + """ + Parse a bytestring as a full PROXY protocol header. + + @param line: A bytestring that represents a valid HAProxy PROXY + protocol version 2 header. + @type line: bytes + + @return: A L{_interfaces.IProxyInfo} containing the + parsed data. + + @raises InvalidProxyHeader: If the bytestring does not represent a + valid PROXY header. + """ + prefix = line[:12] + addrInfo = None + with convertError(IndexError, InvalidProxyHeader): + # Use single value slices to ensure bytestring values are returned + # instead of int in PY3. + versionCommand = ord(line[12:13]) + familyProto = ord(line[13:14]) + + if prefix != cls.PREFIX: + raise InvalidProxyHeader() + + version, command = versionCommand & _HIGH, versionCommand & _LOW + if version not in cls.VERSIONS or command not in cls.COMMANDS: + raise InvalidProxyHeader() + + if cls.COMMANDS[command] == _LOCALCOMMAND: + return _info.ProxyInfo(line, None, None) + + family, netproto = familyProto & _HIGH, familyProto & _LOW + with convertError(ValueError, InvalidNetworkProtocol): + family = NetFamily.lookupByValue(family) + netproto = NetProtocol.lookupByValue(netproto) + if ( + family is NetFamily.UNSPEC or + netproto is NetProtocol.UNSPEC + ): + return _info.ProxyInfo(line, None, None) + + addressFormat = cls.ADDRESSFORMATS[familyProto] + addrInfo = line[16:16+struct.calcsize(addressFormat)] + if family is NetFamily.UNIX: + with convertError(struct.error, MissingAddressData): + source, dest = struct.unpack(addressFormat, addrInfo) + return _info.ProxyInfo( + line, + address.UNIXAddress(source.rstrip(b'\x00')), + address.UNIXAddress(dest.rstrip(b'\x00')), + ) + + addrType = 'TCP' + if netproto is NetProtocol.DGRAM: + addrType = 'UDP' + addrCls = address.IPv4Address + addrParser = cls._bytesToIPv4 + if family is NetFamily.INET6: + addrCls = address.IPv6Address + addrParser = cls._bytesToIPv6 + + with convertError(struct.error, MissingAddressData): + info = struct.unpack(addressFormat, addrInfo) + source, dest, sPort, dPort = info + + return _info.ProxyInfo( + line, + addrCls(addrType, addrParser(source), sPort), + addrCls(addrType, addrParser(dest), dPort), + ) |