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); } } }
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; }
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; }
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); } }
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]; } }
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); } }
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); }
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; }
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)); }
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); }
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; } } }
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; }
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); }
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; }
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; }
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)); }
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; } }
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?... }
// 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; }
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>()); }
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); }
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 ) ); } }
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); }
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)); }
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); }
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); } } }
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); }
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 ) ); } }