Exemple #1
1
PPPoE::PPPoE(const uint8_t* buffer, uint32_t total_sz)
    : tags_size_() {
    InputMemoryStream stream(buffer, total_sz);
    stream.read(header_);
    stream.size(std::min(stream.size(), (size_t)payload_length()));
    // If this is a session data packet
    if (code() == 0) {
        if (stream) {
            inner_pdu(
                new RawPDU(stream.pointer(), stream.size())
            );
        }
    }
    else {
        while (stream) {
            TagTypes opt_type = static_cast<TagTypes>(stream.read<uint16_t>());
            uint16_t opt_len = stream.read_be<uint16_t>();
            if (!stream.can_read(opt_len)) {
                throw malformed_packet();
            }
            add_tag(tag(opt_type, opt_len, stream.pointer()));
            stream.skip(opt_len);
        }
    }
}
Exemple #2
0
int
unpack_msgpack_uint32(struct qserver *server, uint32_t *val, unsigned char **datap, unsigned char *last, int raw)
{


	if (!raw) {
		if (*datap > last) {
			malformed_packet(server, "packet too small");
			return 0;
		}

		if (**datap != 0xce) {
			malformed_packet(server, "invalid uint32 type 0x%02hhx", **datap);
			return 0;
		}

		(*datap)++;
	}

	if (*datap + 4 > last) {
		malformed_packet(server, "packet too small");
		return 0;
	}

	*val = (uint32_t)(*datap)[3] |
		((uint32_t)(*datap)[2] << 8) |
		((uint32_t)(*datap)[1] << 16) |
		((uint32_t)(*datap)[0] << 24);
	*datap += 2;

	return 1;
}
Exemple #3
0
int
unpack_msgpack_raw_len(struct qserver *server, char **valp, unsigned char **datap, unsigned char *last, uint32_t len)
{
	char *data;

	debug(4, "raw_len: 0x%lu\n", (unsigned long)len);

	if (*datap + len > last) {
		malformed_packet(server, "packet too small");
		return 0;
	}

	if (NULL == (data = malloc(len + 1))) {
		malformed_packet(server, "out of memory");
		return 0;
	}

	memcpy(data, *datap, len);
	data[len] = '\0';

	*valp = data;
	(*datap) += len;

	return 1;
}
Exemple #4
0
DHCP::DHCP(const uint8_t* buffer, uint32_t total_sz) 
: BootP(buffer, total_sz, 0), size_(sizeof(uint32_t)) {
    InputMemoryStream stream(buffer, total_sz);
    stream.skip(BootP::header_size() - vend().size());
    const uint32_t magic_number = stream.read<uint32_t>();
    if (magic_number != Endian::host_to_be<uint32_t>(0x63825363)) {
        throw malformed_packet();
    }
    // While there's data left
    while (stream) {
        OptionTypes option_type;
        uint8_t option_length = 0;
        option_type = (OptionTypes)stream.read<uint8_t>();
        // We should only read the length if it's not END nor PAD
        if (option_type != END && option_type != PAD) {
            option_length = stream.read<uint8_t>();
        }
        // Make sure we can read the payload size
        if (!stream.can_read(option_length)) {
            throw malformed_packet();
        }
        add_option(option(option_type, option_length, stream.pointer()));
        stream.skip(option_length);
    }
}
Exemple #5
0
DHCP::DHCP(const uint8_t *buffer, uint32_t total_sz) 
: BootP(buffer, total_sz, 0), _size(sizeof(uint32_t))
{
    buffer += BootP::header_size() - vend().size();
    total_sz -= BootP::header_size() - vend().size();
    uint8_t args[2] = {0};
    uint32_t uint32_t_buffer;
    std::memcpy(&uint32_t_buffer, buffer, sizeof(uint32_t));
    if(total_sz < sizeof(uint32_t) || uint32_t_buffer != Endian::host_to_be<uint32_t>(0x63825363))
        throw malformed_packet();
    buffer += sizeof(uint32_t);
    total_sz -= sizeof(uint32_t);
    while(total_sz) {
        for(unsigned i(0); i < 2; ++i) {
            args[i] = *(buffer++);
            total_sz--;
            if(args[0] == END || args[0] == PAD) {
                args[1] = 0;
                i = 2;
            }
            else if(!total_sz)
                throw malformed_packet();
        }
        if(total_sz < args[1])
            throw malformed_packet();
        add_option(
            option((OptionTypes)args[0], args[1], buffer)
        );
        buffer += args[1];
        total_sz -= args[1];
    }
}
Exemple #6
0
PPPoE::PPPoE(const uint8_t *buffer, uint32_t total_sz) 
: _tags_size()
{
    if(total_sz < sizeof(_header))
        throw malformed_packet();
    std::memcpy(&_header, buffer, sizeof(_header));
    buffer += sizeof(_header);
    total_sz -= sizeof(_header);
    total_sz = std::min(total_sz, (uint32_t)payload_length());
    const uint8_t *end = buffer + total_sz;
    while(buffer < end) {
        if(buffer + sizeof(uint32_t) * 2 > end)
            throw malformed_packet();
        uint16_t opt_type;
        std::memcpy(&opt_type, buffer, sizeof(uint16_t));
        uint16_t opt_len;
        std::memcpy(&opt_len, buffer + sizeof(uint16_t), sizeof(uint16_t));
        buffer += sizeof(uint16_t) * 2;
        total_sz -= sizeof(uint16_t) * 2;
        if(Endian::be_to_host(opt_len) > total_sz)
            throw malformed_packet();
        add_tag(
            tag(
                static_cast<TagTypes>(opt_type), 
                Endian::be_to_host(opt_len), 
                buffer
            )
        );
        buffer += Endian::be_to_host(opt_len);
        total_sz -= Endian::be_to_host(opt_len);
    }
}
Exemple #7
0
int
unpack_msgpack_uint16(struct qserver *server, uint16_t *val, unsigned char **datap, unsigned char *last, int raw)
{
	if (!raw) {
		if (*datap > last) {
			malformed_packet(server, "packet too small");
			return (0);
		}

		if (**datap != 0xcd) {
			malformed_packet(server, "invalid uint16 type 0x%02hhx", **datap);
			return (0);
		}

		(*datap)++;
	}

	if (*datap + 2 > last) {
		malformed_packet(server, "packet too small");
		return (0);
	}
	*val = (uint16_t)(*datap)[1] | ((uint16_t)(*datap)[0] << 8);
	*datap += 2;

	return (1);
}
Exemple #8
0
query_status_t deal_with_ottdmaster_packet(struct qserver *server, char *rawpkt, int pktlen)
{
	unsigned num;
	server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
	server->server_name = MASTER;

	if(swap_short_from_little(rawpkt) != pktlen)
	{
		malformed_packet( server, "invalid packet length" );
		return PKT_ERROR;
	}
	if(rawpkt[2] != 7)
	{
		malformed_packet( server, "invalid packet type" );
		return PKT_ERROR;
	}

	if(rawpkt[3] != 1)
	{
		malformed_packet( server, "invalid packet version" );
		return PKT_ERROR;
	}

	num = swap_short_from_little(&rawpkt[4]);
	rawpkt += 6;
	pktlen -= 6;
	if( num && num*6 <= pktlen )
	{
		unsigned i;
		server->master_pkt = (char*)realloc(server->master_pkt, server->master_pkt_len + pktlen );
		memset(server->master_pkt + server->master_pkt_len, 0, pktlen );
		server->master_pkt_len += pktlen;
		for( i = 0; i < num * 6; i += 6 )
		{
			memcpy(&server->master_pkt[i], &rawpkt[i], 4);
			server->master_pkt[i+4] = rawpkt[i+5];
			server->master_pkt[i+5] = rawpkt[i+4];
		}
		server->n_servers += num;
	}
	else
	{
		malformed_packet( server, "invalid packet" );
		return PKT_ERROR;
	}

	bind_sockets();

	return DONE_AUTO;
}
Exemple #9
0
Dot11::Dot11(const uint8_t *buffer, uint32_t total_sz) 
: _options_size(0) 
{
    if(total_sz < sizeof(_header))
        throw malformed_packet();
    std::memcpy(&_header, buffer, sizeof(_header));
}
Exemple #10
0
PDU::metadata EAPOL::extract_metadata(const uint8_t *buffer, uint32_t total_sz) {
    if (TINS_UNLIKELY(total_sz < sizeof(eapol_header))) {
        throw malformed_packet();
    }
    const eapol_header* header = (const eapol_header*)buffer;
    uint32_t advertised_size = Endian::be_to_host<uint16_t>(header->length) + 4;
    return metadata(min(total_sz, advertised_size), pdu_flag, PDU::UNKNOWN);
}
Exemple #11
0
PPI::PPI(const uint8_t *buffer, uint32_t total_sz) {
    if(total_sz < sizeof(_header))
        throw malformed_packet();
    std::memcpy(&_header, buffer, sizeof(_header));
    if(length() > total_sz || length() < sizeof(_header))
        throw malformed_packet();
    buffer += sizeof(_header);
    total_sz -= sizeof(_header);
    // There are some options
    const size_t options_length = length() - sizeof(_header);
    if(options_length > 0) {
        _data.assign(buffer, buffer + options_length);
        buffer += options_length;
        total_sz -= static_cast<uint32_t>(options_length);
    }
    if(total_sz > 0) {
        switch(dlt()) {
            case DLT_IEEE802_11:
                #ifdef HAVE_DOT11
                    parse_80211(buffer, total_sz);
                #else
                    throw protocol_disabled();
                #endif
                break;
            case DLT_EN10MB:
                if(Internals::is_dot3(buffer, total_sz))
                    inner_pdu(new Dot3(buffer, total_sz));
                else
                    inner_pdu(new EthernetII(buffer, total_sz));
                break;
            case DLT_IEEE802_11_RADIO:
                #ifdef HAVE_DOT11
                    inner_pdu(new RadioTap(buffer, total_sz));
                #else
                    throw protocol_disabled();
                #endif
                break;
            case DLT_NULL:
                inner_pdu(new Loopback(buffer, total_sz));
                break;
            case DLT_LINUX_SLL:
                inner_pdu(new Tins::SLL(buffer, total_sz));
                break;
        }
    }
}
Exemple #12
0
Dot11ControlTA::Dot11ControlTA(const uint8_t *buffer, uint32_t total_sz) : Dot11Control(buffer, total_sz) {
    buffer += sizeof(ieee80211_header);
    total_sz -= sizeof(ieee80211_header);
    if(total_sz < sizeof(_taddr))
        throw malformed_packet();
    //std::memcpy(_taddr, buffer, sizeof(_taddr));
    _taddr = buffer;
}
Exemple #13
0
BootP::BootP(const uint8_t* buffer, uint32_t total_sz, uint32_t vend_field_size) 
: vend_(vend_field_size) {
    InputMemoryStream stream(buffer, total_sz);
    stream.read(bootp_);
    if (!stream.can_read(vend_field_size)) {
        throw malformed_packet();
    }
    stream.read(vend_, vend_field_size);
}
Exemple #14
0
Dot11 *Dot11::from_bytes(const uint8_t *buffer, uint32_t total_sz) {
    // We only need the control field, the length of the PDU will depend on the flags set.
    
    // This should be sizeof(ieee80211_header::control), but gcc 4.2 complains
    if(total_sz < 2)
        throw malformed_packet();
    const ieee80211_header *hdr = (const ieee80211_header*)buffer;
    Dot11 *ret = 0;
    if(hdr->control.type == MANAGEMENT) {
        if(hdr->control.subtype == BEACON)
            ret = new Dot11Beacon(buffer, total_sz);
        else if(hdr->control.subtype == DISASSOC)
            ret = new Dot11Disassoc(buffer, total_sz);
        else if(hdr->control.subtype == ASSOC_REQ)
            ret = new Dot11AssocRequest(buffer, total_sz);
        else if(hdr->control.subtype == ASSOC_RESP)
            ret = new Dot11AssocResponse(buffer, total_sz);
        else if(hdr->control.subtype == REASSOC_REQ)
            ret = new Dot11ReAssocRequest(buffer, total_sz);
        else if(hdr->control.subtype == REASSOC_RESP)
            ret = new Dot11ReAssocResponse(buffer, total_sz); 
        else if(hdr->control.subtype == AUTH)
            ret = new Dot11Authentication(buffer, total_sz); 
        else if(hdr->control.subtype == DEAUTH)
            ret = new Dot11Deauthentication(buffer, total_sz); 
        else if(hdr->control.subtype == PROBE_REQ)
            ret = new Dot11ProbeRequest(buffer, total_sz); 
        else if(hdr->control.subtype == PROBE_RESP)
            ret = new Dot11ProbeResponse(buffer, total_sz); 
    }
    else if(hdr->control.type == DATA){
        if(hdr->control.subtype <= 4)
            ret = new Dot11Data(buffer, total_sz);
        else
            ret = new Dot11QoSData(buffer, total_sz);
    }
    else if(hdr->control.type == CONTROL){
        if(hdr->control.subtype == ACK)
            ret = new Dot11Ack(buffer, total_sz);
        else if(hdr->control.subtype == CF_END)
            ret = new Dot11CFEnd(buffer, total_sz);
        else if(hdr->control.subtype == CF_END_ACK)
            ret = new Dot11EndCFAck(buffer, total_sz);
        else if(hdr->control.subtype == PS)
            ret = new Dot11PSPoll(buffer, total_sz);
        else if(hdr->control.subtype == RTS)
            ret = new Dot11RTS(buffer, total_sz);
        else if(hdr->control.subtype == BLOCK_ACK)
            ret = new Dot11BlockAck(buffer, total_sz);
        else if(hdr->control.subtype == BLOCK_ACK_REQ)
            ret = new Dot11BlockAckRequest(buffer, total_sz);
    }
    if(ret == 0)
        ret = new Dot11(buffer, total_sz);
    return ret;
}
Exemple #15
0
uint32_t Dot11Data::init(const uint8_t *buffer, uint32_t total_sz) {
    const uint8_t *start_ptr = buffer;
    uint32_t sz = Dot11::header_size();
    buffer += sz;
    total_sz -= sz;
    if(total_sz < sizeof(_ext_header))
        throw malformed_packet();
    std::memcpy(&_ext_header, buffer, sizeof(_ext_header));
    buffer += sizeof(_ext_header);
    total_sz -= sizeof(_ext_header);
    if(from_ds() && to_ds()) {
        if(total_sz < _addr4.size())
            throw malformed_packet();
        _addr4 = buffer;
        buffer += _addr4.size();
        total_sz -= _addr4.size();
    }
    return buffer - start_ptr;
}
Exemple #16
0
ARP::ARP(const uint8_t *buffer, uint32_t total_sz) 
{
    if(total_sz < sizeof(arphdr))
        throw malformed_packet();
    memcpy(&_arp, buffer, sizeof(arphdr));
    total_sz -= sizeof(arphdr);
    //TODO: Check whether this should be removed or not.
    if(total_sz)
        inner_pdu(new RawPDU(buffer + sizeof(arphdr), total_sz));
}
Exemple #17
0
DHCPv6::DHCPv6(const uint8_t *buffer, uint32_t total_sz) 
: options_size() 
{
    if(total_sz == 0) 
        throw malformed_packet();
    // Relay Agent/Server Messages
    bool is_relay_msg = (buffer[0] == 12 || buffer[0] == 13);
    uint32_t required_size = is_relay_msg ? 2 : 4;
    if(total_sz < required_size)
        throw malformed_packet();
    std::copy(buffer, buffer + required_size, header_data);
    buffer += required_size;
    total_sz -= required_size;
    if(is_relay_message()) {
        if(total_sz < ipaddress_type::address_size * 2)
            throw malformed_packet();
        link_addr = buffer;
        peer_addr = buffer + ipaddress_type::address_size;
        buffer += ipaddress_type::address_size * 2;
        total_sz -= ipaddress_type::address_size * 2;
    }
    options_size = total_sz;
    while(total_sz) {
        if(total_sz < sizeof(uint16_t) * 2) 
            throw malformed_packet();
        
        uint16_t opt;
        std::memcpy(&opt, buffer, sizeof(uint16_t));
        opt = Endian::be_to_host(opt);
        uint16_t data_size;
        std::memcpy(&data_size, buffer + sizeof(uint16_t), sizeof(uint16_t));
        data_size = Endian::be_to_host(data_size);
        if(total_sz - sizeof(uint16_t) * 2 < data_size)
            throw malformed_packet();
        buffer += sizeof(uint16_t) * 2;
        add_option(
            option(opt, buffer, buffer + data_size)
        );
        buffer += data_size;
        total_sz -= sizeof(uint16_t) * 2 + data_size;
    }
}
Exemple #18
0
BootP::BootP(const uint8_t *buffer, uint32_t total_sz, uint32_t vend_field_size) 
: _vend(vend_field_size) 
{
    if(total_sz < sizeof(bootphdr) + vend_field_size)
        throw malformed_packet();
    std::memcpy(&_bootp, buffer, sizeof(bootphdr));
    buffer += sizeof(bootphdr);
    total_sz -= sizeof(bootphdr);
    _vend.assign(buffer, buffer + vend_field_size);
    // Maybe RawPDU on what is left on the buffer?...
}
Exemple #19
0
// This method finds the extra flags field size, taking into account other
// set of flags that may appear if the "ext" bit is on/.
uint32_t RadioTap::find_extra_flag_fields_size(const uint8_t* buffer, uint32_t total_sz) {
    const flags_type* ptr = (const flags_type*)buffer;
    while (ptr->ext == 1) {
        if (total_sz < sizeof(flags_type)) {
            throw malformed_packet();
        }
        ++ptr;
    }

    return (const uint8_t*)ptr - buffer;
}
Exemple #20
0
int
unpack_msgpack_raw(struct qserver *server, char **valp, unsigned char **datap, unsigned char *last)
{
	unsigned char type, len;

	if (*datap + 1 > last) {
		malformed_packet(server, "packet too small");
		return 0;
	}

	type = (**datap & 0xa0);
	len = (**datap & 0x1f);
	if (0xa0 != type) {
		malformed_packet(server, "invalid raw type 0x%02hhx", **datap);
		return 0;
	}
	(*datap)++;

	return unpack_msgpack_raw_len(server, valp, datap, last, (uint32_t)len);
}
void RSNInformation::init(const uint8_t* buffer, uint32_t total_sz) {
    InputMemoryStream stream(buffer, total_sz);
    version(stream.read_le<uint16_t>());
    group_suite((RSNInformation::CypherSuites)stream.read_le<uint32_t>());
    int pairwise_cyphers_size = stream.read_le<uint16_t>();
    if (!stream.can_read(pairwise_cyphers_size)) {
        throw malformed_packet();
    }
    while (pairwise_cyphers_size--) {
        add_pairwise_cypher((RSNInformation::CypherSuites)stream.read_le<uint32_t>());
    }
    int akm_cyphers_size = stream.read_le<uint16_t>();
    if (!stream.can_read(akm_cyphers_size)) {
        throw malformed_packet();
    }
    while (akm_cyphers_size--) {
        add_akm_cypher((RSNInformation::AKMSuites)stream.read_le<uint32_t>());
    }
    capabilities(stream.read_le<uint16_t>());
}
Exemple #22
0
int
unpack_msgpack_pos_fixnum(struct qserver *server, uint8_t *val, unsigned char **datap, unsigned char *last, int raw)
{
	if (!raw) {
		if (*datap > last) {
			malformed_packet(server, "packet too small");
			return (0);
		}

		if ((**datap & 0x80) != 0) {
			malformed_packet(server, "invalid positive fixnum type 0x%02hhx", **datap);
			return (0);
		}
	}

	*val = **datap;
	(*datap)++;

	return (1);
}
Exemple #23
0
PKTAP::PKTAP(const uint8_t* buffer, uint32_t total_sz) {
    if (total_sz < sizeof(pktap_header)) {
        throw malformed_packet();
    }
    memcpy(&header_, buffer, sizeof(header_));
    uint32_t header_length = header_.length;
    if (header_length > total_sz) {
        throw malformed_packet();
    }
    buffer += header_length;
    total_sz -= header_length;
    if (header_.next && total_sz > 0) {
        inner_pdu(
            Internals::pdu_from_dlt_flag(
                header_.dlt, 
                buffer, 
                total_sz
            )
        );
    }
}
Exemple #24
0
Dot11Disassoc::Dot11Disassoc(const uint8_t *buffer, uint32_t total_sz) 
: Dot11ManagementFrame(buffer, total_sz) {
    uint32_t sz = management_frame_size();
    buffer += sz;
    total_sz -= sz;
    if(total_sz < sizeof(_body))
        throw malformed_packet();
    memcpy(&_body, buffer, sizeof(_body));
    buffer += sizeof(_body);
    total_sz -= sizeof(_body);
    parse_tagged_parameters(buffer, total_sz);
}
Exemple #25
0
Dot11BlockAck::Dot11BlockAck(const uint8_t *buffer, uint32_t total_sz) : Dot11ControlTA(buffer, total_sz) {
    uint32_t padding = controlta_size();
    buffer += padding;
    total_sz -= padding;
    if(total_sz < sizeof(_bitmap) + sizeof(_bar_control) + sizeof(_start_sequence))
        throw malformed_packet();
    std::memcpy(&_bar_control, buffer, sizeof(_bar_control));
    buffer += sizeof(_bar_control);
    std::memcpy(&_start_sequence, buffer, sizeof(_start_sequence));
    buffer += sizeof(_start_sequence);
    std::memcpy(&_bitmap, buffer, sizeof(_bitmap));
}
Exemple #26
0
DNSResourceRecord::DNSResourceRecord(const uint8_t *buffer, uint32_t size) 
{
    const uint8_t *buffer_end = buffer + size;
    Internals::smart_ptr<DNSRRImpl>::type tmp_impl;
    if((*buffer & 0xc0)) {
        uint16_t offset(*reinterpret_cast<const uint16_t*>(buffer));
        offset = Endian::be_to_host(offset) & 0x3fff;
        tmp_impl.reset(new OffsetedDNSRRImpl(Endian::host_to_be(offset)));
        buffer += sizeof(uint16_t);
    }
    else {
        const uint8_t *str_end(buffer);
        while(str_end < buffer_end && *str_end)
            str_end++;
        if(str_end == buffer_end)
            throw malformed_packet();
        //str_end++;
        tmp_impl.reset(new NamedDNSRRImpl(buffer, str_end));
        buffer = ++str_end;
    }
    if(buffer + sizeof(info_) > buffer_end)
        throw malformed_packet();
    std::memcpy(&info_, buffer, sizeof(info_));
    buffer += sizeof(info_);
    if(buffer + sizeof(uint16_t) > buffer_end)
        throw malformed_packet();

    // Store the option size.
    data.resize(
        Endian::be_to_host(*reinterpret_cast<const uint16_t*>(buffer))
    );
    buffer += sizeof(uint16_t);
    if(buffer + data.size() > buffer_end)
        throw malformed_packet();
    if(contains_dname(info_.type) || data.size() != sizeof(uint32_t))
        std::copy(buffer, buffer + data.size(), data.begin());
    else if(data.size() == sizeof(uint32_t))
        *(uint32_t*)&data[0] = *(uint32_t*)buffer;
    impl = tmp_impl.release();
}
ICMPExtension::ICMPExtension(const uint8_t* buffer, uint32_t total_sz) {
    InputMemoryStream stream(buffer, total_sz);

    uint16_t length = stream.read_be<uint16_t>();
    extension_class_ = stream.read<uint8_t>();
    extension_type_ = stream.read<uint8_t>();
    // Length is BASE_HEADER_SIZE + payload size, make sure it's valid
    if (length < BASE_HEADER_SIZE || length - BASE_HEADER_SIZE > stream.size()) {
        throw malformed_packet();
    }
    length -= BASE_HEADER_SIZE;
    stream.read(payload_, length);
}
Exemple #28
0
void Dot11::parse_tagged_parameters(InputMemoryStream& stream) {
    if (stream) {
        while (stream.size() >= 2) {
            OptionTypes opcode = static_cast<OptionTypes>(stream.read<uint8_t>());
            uint8_t length = stream.read<uint8_t>();
            if (!stream.can_read(length)) {
                throw malformed_packet();
            }
            add_tagged_option(opcode, length, stream.pointer());
            stream.skip(length);
        }
    }
}
Exemple #29
0
RSNEAPOL::RSNEAPOL(const uint8_t *buffer, uint32_t total_sz) 
: EAPOL(buffer, total_sz)
{
    buffer += sizeof(eapolhdr);
    total_sz -= sizeof(eapolhdr);
    if(total_sz < sizeof(_header))
        throw malformed_packet();
    std::memcpy(&_header, buffer, sizeof(_header));
    buffer += sizeof(_header);
    total_sz -= sizeof(_header);
    if(total_sz == wpa_length())
        _key.assign(buffer, buffer + total_sz);
}
Exemple #30
0
IPSecAH::IPSecAH(const uint8_t* buffer, uint32_t total_sz) {
    InputMemoryStream stream(buffer, total_sz);
    stream.read(header_);
    const uint32_t ah_len = 4 * (static_cast<uint16_t>(length()) + 2);
    if (ah_len < sizeof(header_)) {
        throw malformed_packet();
    }
    const uint32_t icv_length = ah_len - sizeof(header_);
    if (!stream.can_read(icv_length)) {
        throw malformed_packet();
    }
    stream.read(icv_, icv_length);
    if (stream) {
        inner_pdu(
            Internals::pdu_from_flag(
                static_cast<Constants::IP::e>(next_header()),
                stream.pointer(), 
                stream.size(), 
                true
            )
        );
    }
}