PtrPacket BaseSniffer::next_packet() { sniff_data data; const int iface_type = pcap_datalink(handle_); pcap_handler handler = 0; if (extract_raw_) { handler = &sniff_loop_handler<RawPDU>; } else if (iface_type == DLT_EN10MB) { handler = sniff_loop_eth_handler; } else if (iface_type == DLT_IEEE802_11_RADIO) { #ifdef TINS_HAVE_DOT11 handler = &sniff_loop_handler<RadioTap>; #else throw protocol_disabled(); #endif } else if (iface_type == DLT_IEEE802_11) { #ifdef TINS_HAVE_DOT11 handler = sniff_loop_dot11_handler; #else throw protocol_disabled(); #endif } #ifdef DLT_PKTAP else if (iface_type == DLT_PKTAP) { handler = &sniff_loop_handler<PKTAP>; } #endif // DLT_PKTAP else if (iface_type == DLT_NULL) { handler = &sniff_loop_handler<Tins::Loopback>; } else if (iface_type == DLT_LINUX_SLL) { handler = &sniff_loop_handler<SLL>; } else if (iface_type == DLT_PPI) { handler = &sniff_loop_handler<PPI>; } else { throw unknown_link_type(); } // keep calling pcap_loop until a well-formed packet is found. while (data.pdu == 0 && data.packet_processed) { data.packet_processed = false; if (pcap_loop(handle_, 1, handler, (u_char*)&data) < 0) { return PtrPacket(0, Timestamp()); } } return PtrPacket(data.pdu, data.tv); }
PDU* pdu_from_dlt_flag(int flag, const uint8_t* buffer, uint32_t size, bool rawpdu_on_no_match) { switch (flag) { case DLT_EN10MB: return new EthernetII(buffer, size); #ifdef TINS_HAVE_DOT11 case DLT_IEEE802_11_RADIO: return new RadioTap(buffer, size); case DLT_IEEE802_11: return Dot11::from_bytes(buffer, size); #else // TINS_HAVE_DOT11 case DLT_IEEE802_11_RADIO: case DLT_IEEE802_11: throw protocol_disabled(); #endif // TINS_HAVE_DOT11 case DLT_NULL: return new Loopback(buffer, size); case DLT_LINUX_SLL: return new SLL(buffer, size); case DLT_PPI: return new PPI(buffer, size); default: return rawpdu_on_no_match ? new RawPDU(buffer, size) : 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; } } }