def parse(cls, packed_value): try: cls.is_valid_length(packed_value) return cls(bytes_data=struct.unpack("!4s", packed_value)[0]) except (ValueError, struct.error) as exception: raise MessageParseError("%s unable to unpack." % cls.__name__) from exception
def extract_attributes(cls, attributes_data, attributes, attributes_to_concat): """ Extracts Radius Attributes from a packed payload. Keeps track of attribute ordering. Args: attributes_data (): data to extract from (input). attributes: attributes extracted (output variable). attributes_to_concat (dict): (output variable). Raises: MessageParseError: RadiusAttribute.parse will raise error if it cannot parse the attribute's data """ total_length = len(attributes_data) pos = 0 index = -1 last_attribute = -1 while pos < total_length: try: type_, attr_length = struct.unpack( "!BB", attributes_data[pos:pos + Attribute.HEADER_SIZE]) except struct.error as exception: raise MessageParseError('Unable to unpack first 2 bytes of attribute header') \ from exception data = attributes_data[pos + Attribute.HEADER_SIZE:pos + attr_length] pos += attr_length packed_value = data[:attr_length - Attribute.HEADER_SIZE] try: attribute = ATTRIBUTE_TYPES[type_].parse(packed_value) except KeyError as exception: raise MessageParseError( 'Cannot find parser for RADIUS attribute %s' % type_) from exception # keep track of where the concated AVP should be in the attributes list. # required so the hashing gives correct hash. if attribute.DATA_TYPE != Concat or last_attribute != attribute.TYPE: index += 1 last_attribute = attribute.TYPE if attribute.DATA_TYPE.DATA_TYPE_VALUE == Concat.DATA_TYPE_VALUE: if attribute.TYPE not in attributes_to_concat: attributes_to_concat[attribute.TYPE] = [] attributes_to_concat[attribute.TYPE].append((attribute, index)) attributes.append(attribute)
def parse(cls, packed_value): # TODO Vsa.parse does not currently separate the vendor-id from the vsa-data # we could do that at some point (e.g. if we wanted to use Vendor-Specific) try: cls.is_valid_length(packed_value) return cls(struct.unpack("!%ds" % len(packed_value), packed_value)[0]) except (ValueError, struct.error) as exception: raise MessageParseError("%s unable to unpack." % cls.__name__) from exception
def parse(packed_message, secret, radius_lifecycle=None): """ Args: packed_message: secret (str): Shared sceret between chewie and RADIUS server. radius_lifecycle: RadiusLifecycle object Returns: RadiusPacket - RadiusAccessChallenge/RadiusAccessRequest/ RadiusAccessAccept/RadiusAccessFailure Raises: MessageParseError: if packed_message cannot be parsed """ try: code, packet_id, length, authenticator = struct.unpack( "!BBH16s", packed_message[:RADIUS_HEADER_LENGTH]) except struct.error as exception: raise MessageParseError('Unable to unpack first 20 bytes of RADIUS header') \ from exception if code in PACKET_TYPE_PARSERS.keys(): radius_packet = PACKET_TYPE_PARSERS[code]( packet_id, authenticator, RadiusAttributesList.parse( packed_message[RADIUS_HEADER_LENGTH:])) if code == Radius.ACCESS_REQUEST: request_authenticator = authenticator else: try: request_authenticator = radius_lifecycle.packet_id_to_request_authenticator[ packet_id] except KeyError as exception: raise MessageParseError('Unknown RAIDUS packet_id: %s' % packet_id, ) \ from exception try: return radius_packet.validate_packet( secret, request_authenticator=request_authenticator, code=code) except (InvalidMessageAuthenticatorError, InvalidResponseAuthenticatorError) as exception: raise MessageParseError("Unable to parse Radius packet") \ from exception raise MessageParseError("Unable to parse radius code: %d" % code)
def parse(cls, packed_value): # TODO how do we want to do valid length checking here? # # Parsing is (generally) for packets coming from the radius server. # Packing is (generally) for packets going to the radius server. # # Therefore we error out if length is too long (you are not allowed to have AVP that are too long) try: return cls(struct.unpack("!%ds" % len(packed_value), packed_value)[0]) except struct.error as exception: raise MessageParseError("%s unable to unpack." % cls.__name__) from exception
def parse(cls, code, packet_id, packed_message): """ Returns: EapIdentity. Raises: MessageParseError if packed message cannot be decoded. """ try: identity = packed_message.decode() except UnicodeDecodeError as exception: raise MessageParseError("%s unable to decode identity" % cls.__name__) from exception return cls(code, packet_id, identity)
def parse(packed_message): """ Args: packed_message: Returns: Eap*** object. Raises: MessageParseError if packed_message cannot be parsed. """ try: code, packet_id, length = struct.unpack( "!BBH", packed_message[:EAP_HEADER_LENGTH]) except struct.error as exception: raise MessageParseError( "unable to unpack EAP header (4 bytes)") from exception if code in (Eap.REQUEST, Eap.RESPONSE): try: packet_type, = struct.unpack( "!B", packed_message[EAP_HEADER_LENGTH:EAP_HEADER_LENGTH + EAP_TYPE_LENGTH]) except struct.error as exception: raise MessageParseError("EAP unable to unpack packet_type byte") \ from exception data = packed_message[EAP_HEADER_LENGTH + EAP_TYPE_LENGTH:length] try: return PARSERS[packet_type](code, packet_id, data) except KeyError as exception: raise MessageParseError("EAP packet_type: %s not supported" % packet_type) \ from exception elif code == Eap.SUCCESS: return EapSuccess(packet_id) elif code == Eap.FAILURE: return EapFailure(packet_id) raise MessageParseError("Got Eap packet with bad code: %s" % packed_message)
def parse(cls, code, packet_id, packed_msg): """ Returns: EapLegacyNak. Raises: MessageParseError if cannot unpack packed_message """ value_len = len(packed_msg) try: desired_auth_types = struct.unpack("!%ds" % value_len, packed_msg) except struct.error as exception: raise MessageParseError("%s unable to unpack." % cls.__name__) from exception return cls(code, packet_id, desired_auth_types)
def parse(cls, code, packet_id, packed_message): """ Returns: EapMd5Challenge. Raises: MessageParseError if cannot unpack packed_message """ try: value_length, = struct.unpack("!B", packed_message[:1]) except struct.error as exception: raise MessageParseError("%s unable to unpack first byte" % cls.__name__) \ from exception challenge = packed_message[1:1 + value_length] extra_data = packed_message[1 + value_length:] return cls(code, packet_id, challenge, extra_data)
def ethernet_parse(packed_message): """Parses the ethernet header part, and payload Args: packed_message: Returns: ***Message & destination mac address. Raises: MessageParseError: the packed_message cannot be parsed.""" ethernet_packet = EthernetPacket.parse(packed_message) if ethernet_packet.ethertype != 0x888e: raise MessageParseError( "Ethernet packet with bad ethertype received: %s" % ethernet_packet) return MessageParser.one_x_parse(ethernet_packet.data, ethernet_packet.src_mac), \ ethernet_packet.dst_mac
def one_x_parse(data, src_mac): """Parses the 1x header (version and packet type) part of the packet, and the payload. Args: data: src_mac (MacAddress): source mac address of the data packet. Raises: MessageParseError: the data cannot be parsed.""" auth_8021x = Auth8021x.parse(data) if auth_8021x.packet_type == 0: return MessageParser.eap_parse(auth_8021x.data, src_mac) elif auth_8021x.packet_type == 1: return EapolStartMessage.build(src_mac) elif auth_8021x.packet_type == 2: return EapolLogoffMessage.build(src_mac) raise MessageParseError("802.1x has bad type, expected 0: %s" % auth_8021x)
def parse(cls, packed_message): """construct an Auth8021x from a packed_message Args: packed_message (bytes): Returns: Auth8021x Raises: MessageParseException: if packed_message cannot be parsed successfully. """ try: version, packet_type, length = struct.unpack("!BBH", packed_message[:AUTH_8021X_HEADER_LENGTH]) except struct.error as exception: raise MessageParseError("Auth8021x unable to parse first 4 bytes") from exception data = packed_message[AUTH_8021X_HEADER_LENGTH:AUTH_8021X_HEADER_LENGTH+length] return cls(version, packet_type, data)
def eap_parse(data, src_mac): """Parses the actual EAP payload Args: data: src_mac (MacAddress): source mac address of the data packet Raises: MessageParseError: the data cannot be parsed.""" eap = Eap.parse(data) if isinstance(eap, tuple(PARSERS_TYPES.values())): return EAP_MESSAGES[eap.PACKET_TYPE].build(src_mac, eap) elif isinstance(eap, EapSuccess): return SuccessMessage.build(src_mac, eap) elif isinstance(eap, EapFailure): return FailureMessage.build(src_mac, eap) else: raise MessageParseError("Got bad Eap packet: %s" % eap)
def parse(cls, packed_message): """construct an EthernetPacket from a packed_message Args: packed_message (bytes): Returns: EthernetPacket Raises: MessageParseError: if packed_message cannot be successfully parsed. """ try: dst_mac, src_mac, ethertype = struct.unpack( "!6s6sH", packed_message[:ETHERNET_HEADER_LENGTH]) except struct.error as exception: raise MessageParseError( "Unable to parse Ethernet header (14bytes)") from exception data = packed_message[ETHERNET_HEADER_LENGTH:] return cls(MacAddress(dst_mac), MacAddress(src_mac), ethertype, data)
def parse(cls, code, packet_id, packed_msg): """ Returns: A child of EapTLSBase e.g. EapTLS, EAPTTLS. Raises: MessageParseError if cannot unpack packed_message """ value_len = len(packed_msg) fmt_str = "!B" if value_len > 1: fmt_str += "%ds" % (value_len - 1) try: unpacked = struct.unpack(fmt_str, packed_msg) except struct.error as exception: raise MessageParseError("%s unable to unpack" % cls.__name__) from exception extra_data = b"" if value_len > 1: flags, extra_data = unpacked else: flags = unpacked[0] return cls(code, packet_id, flags, extra_data)