📄 fakepcap.cc
字号:
// -*- mode: c++; c-basic-offset: 4 -*-/* * fakepcap.{cc,hh} -- a faked-up pcap-like interface * Eddie Kohler * * Copyright (c) 2001 International Computer Science Institute * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, subject to the conditions * listed in the Click LICENSE file. These conditions include: you must * preserve this copyright notice, and you cannot mention the copyright * holders in advertising related to the Software without their permission. * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This * notice is a summary of the Click LICENSE file; the license in that file is * legally binding. */#include <click/config.h>#include "fakepcap.hh"#include <clicknet/ip.h>#include <clicknet/ip6.h>#include <clicknet/ether.h>#include <clicknet/fddi.h>#include <clicknet/rfc1483.h>#include <clicknet/wifi.h>#include <clicknet/llc.h>#include <clicknet/ppp.h>#include <click/confparse.hh>CLICK_DECLSstatic const struct dlt_name { const char* name; int dlt;} dlt_names[] = { { "NULL", FAKE_DLT_NULL }, { "IP", FAKE_DLT_RAW }, { "ETHER", FAKE_DLT_EN10MB }, { "FDDI", FAKE_DLT_FDDI }, { "ATM", FAKE_DLT_ATM_RFC1483 }, { "RFC1483", FAKE_DLT_ATM_RFC1483 }, { "ATM_RFC1483", FAKE_DLT_ATM_RFC1483 }, { "802_11", FAKE_DLT_IEEE802_11 }, { "802.11", FAKE_DLT_IEEE802_11 }, { "SLL", FAKE_DLT_LINUX_SLL }, { "AIRONET", FAKE_DLT_AIRONET_HEADER }, { "HDLC", FAKE_DLT_C_HDLC }, { "PPP_HDLC", FAKE_DLT_PPP_HDLC }, { "PPP", FAKE_DLT_PPP }, { "SUNATM", FAKE_DLT_SUNATM }, { "PRISM", FAKE_DLT_PRISM_HEADER }};intfake_pcap_parse_dlt(const String &str){ for (const dlt_name* d = dlt_names; d < dlt_names + (sizeof(dlt_names) / sizeof(dlt_names[0])); d++) if (str == d->name) return d->dlt; uint32_t dlt; if (str.length() >= 2 && str[0] == '#' && cp_unsigned(str.substring(1), &dlt) && dlt < 0x7FFFFFFF) return dlt; else return -1;}Stringfake_pcap_unparse_dlt(int dlt){ for (const dlt_name* d = dlt_names; d < dlt_names + (sizeof(dlt_names) / sizeof(dlt_names[0])); d++) if (dlt == d->dlt) return String::stable_string(d->name); if (dlt < 0) return String::stable_string("<none>"); return "#" + String(dlt);}// Handling FORCE_IP.boolfake_pcap_dlt_force_ipable(int dlt){ return (dlt == FAKE_DLT_RAW || dlt == FAKE_DLT_HOST_RAW || dlt == FAKE_DLT_EN10MB || dlt == FAKE_DLT_SUNATM || dlt == FAKE_DLT_FDDI || dlt == FAKE_DLT_ATM_RFC1483 || dlt == FAKE_DLT_LINUX_SLL || dlt == FAKE_DLT_C_HDLC || dlt == FAKE_DLT_IEEE802_11 || dlt == FAKE_DLT_PRISM_HEADER || dlt == FAKE_DLT_PPP_HDLC || dlt == FAKE_DLT_PPP || dlt == FAKE_DLT_NULL);}intfake_pcap_canonical_dlt(int dlt, bool){ if (dlt == FAKE_DLT_HOST_RAW) return FAKE_DLT_RAW; else return dlt;}#if HAVE_INDIFFERENT_ALIGNMENT#define unaligned_net_short(v) (ntohs(*reinterpret_cast<const uint16_t*>(v)))#define UNALIGNED_NET_SHORT_EQ(x, y) ((x) == htons((y)))#elsestatic inline uint16_tunaligned_net_short(const void *v){ const uint8_t *d = reinterpret_cast<const uint8_t *>(v); return (d[0] << 8) | d[1];}#define UNALIGNED_NET_SHORT_EQ(x, y) (unaligned_net_short(&(x)) == (y))#endif#define IP_ETHERTYPE(et) (UNALIGNED_NET_SHORT_EQ((et), ETHERTYPE_IP) || UNALIGNED_NET_SHORT_EQ((et), ETHERTYPE_IP6))// NB: May change 'p', but will never free it.boolfake_pcap_force_ip(Packet *&p, int dlt){ const click_ip* iph = 0; const uint8_t* data = p->data(); const uint8_t* end_data = p->end_data(); switch (dlt) { case FAKE_DLT_RAW: case FAKE_DLT_HOST_RAW: { iph = reinterpret_cast<const click_ip*>(data); break; } ethernet: case FAKE_DLT_EN10MB: { const click_ether* ethh = reinterpret_cast<const click_ether*>(data); if (data + sizeof(click_ether) <= end_data) { if (IP_ETHERTYPE(ethh->ether_type)) iph = reinterpret_cast<const click_ip*>(ethh + 1); else if (UNALIGNED_NET_SHORT_EQ(ethh->ether_type, ETHERTYPE_8021Q) && data + sizeof(click_ether_vlan) <= end_data) { // XXX don't handle 802.1Q-in-802.1Q const click_ether_vlan* ethvh = reinterpret_cast<const click_ether_vlan*>(ethh); if (IP_ETHERTYPE(ethvh->ether_vlan_encap_proto)) iph = reinterpret_cast<const click_ip*>(ethvh + 1); } } break; } fddi: case FAKE_DLT_FDDI: { const click_fddi* fh = reinterpret_cast<const click_fddi*>(data); if (data + sizeof(click_fddi_snap) > end_data || (fh->fc & FDDI_FC_LLCMASK) != FDDI_FC_LLC_ASYNC) break; data = reinterpret_cast<const uint8_t*>(fh + 1); goto rfc1483; } case FAKE_DLT_SUNATM: data += 4; goto rfc1483; rfc1483: case FAKE_DLT_ATM_RFC1483: { const click_rfc1483* rh = reinterpret_cast<const click_rfc1483*>(data); if (data + sizeof(click_rfc1483) <= end_data && memcmp(&rh->dsap, RFC1483_SNAP_IP_EXPECTED, RFC1483_SNAP_IP_EXPECTED_LEN) == 0 && IP_ETHERTYPE(rh->ether_type)) iph = reinterpret_cast<const click_ip*>(rh + 1); else if (data + 4 <= end_data && rh->dsap == LLC_IP_LSAP && rh->ssap == LLC_IP_LSAP) iph = reinterpret_cast<const click_ip*>(data + 4); else if (data + sizeof(click_rfc1483) <= end_data && rh->dsap == LLC_SNAP_LSAP && rh->ssap == LLC_SNAP_LSAP) {#define OUI_ENCAP_ETHER 0x000000 /* encapsulated Ethernet */#define OUI_CISCO_90 0x0000f8 /* Cisco bridging */#define OUI_RFC2684 0x0080c2 /* RFC 2684 bridged Ethernet */#define PID_RFC2684_ETH_FCS 0x0001 /* Ethernet, with FCS */#define PID_RFC2684_ETH_NOFCS 0x0007 /* Ethernet, without FCS */#define PID_RFC2684_FDDI_FCS 0x0004 /* FDDI, with FCS */#define PID_RFC2684_FDDI_NOFCS 0x000a /* FDDI, without FCS */ uint32_t orgcode = rh->orgcode[0]<<16 + rh->orgcode[1]<<8 + rh->orgcode[2]; if (orgcode == OUI_ENCAP_ETHER || orgcode == OUI_CISCO_90) { data = reinterpret_cast<const uint8_t*>(&rh->ether_type) - 12; goto ethernet; } else if (orgcode == OUI_RFC2684) { uint32_t ethertype = unaligned_net_short(&rh->ether_type); if (ethertype == PID_RFC2684_ETH_FCS || ethertype == PID_RFC2684_ETH_NOFCS) { data = reinterpret_cast<const uint8_t*>(rh + 1); goto ethernet; } else if (ethertype == PID_RFC2684_FDDI_FCS || ethertype == PID_RFC2684_FDDI_NOFCS) { data = reinterpret_cast<const uint8_t*>(rh + 1) + 1; goto fddi; } } } break; } case FAKE_DLT_LINUX_SLL: { CLICK_SIZE_PACKED_STRUCTURE( struct click_linux_sll {, uint16_t sll_pkttype; uint16_t sll_hatype; uint16_t sll_halen; uint8_t sll_addr[8]; uint16_t sll_protocol; }); const click_linux_sll* sllh = reinterpret_cast<const click_linux_sll*>(data); if (data + sizeof(click_linux_sll) <= end_data && IP_ETHERTYPE(sllh->sll_protocol)) iph = reinterpret_cast<const click_ip*>(sllh + 1); break; } c_hdlc: case FAKE_DLT_C_HDLC: { struct click_pcap_hdlc { uint16_t hdlc_address; uint16_t hdlc_protocol; }; const click_pcap_hdlc* hdlch = reinterpret_cast<const click_pcap_hdlc*>(data); if (data + sizeof(click_pcap_hdlc) <= end_data && IP_ETHERTYPE(hdlch->hdlc_protocol)) iph = reinterpret_cast<const click_ip*>(hdlch + 1); break; } case FAKE_DLT_PPP_HDLC: { if (data + 4 > end_data) /* nada */; else if (data[0] == PPP_ADDRESS) { if (data[2] == 0 && (data[3] == PPP_IP || data[3] == PPP_IPV6)) iph = reinterpret_cast<const click_ip*>(data + 4); } else if (data[0] == 0x0F /* CHDLC_UNICAST */ || data[0] == 0x8F /* CHDLC_BCAST */) goto c_hdlc; break; } case FAKE_DLT_PPP: { if (data + 2 <= end_data && data[0] == PPP_ADDRESS && data[1] == PPP_CONTROL) data += 2; if (data + 2 > end_data) /* nada */; else if (data[0] == PPP_IP || data[0] == PPP_IPV6) iph = reinterpret_cast<const click_ip*>(data + 1); else if (data[0] == 0 && (data[1] == PPP_IP || data[1] == PPP_IPV6)) iph = reinterpret_cast<const click_ip*>(data + 2); break; } case FAKE_DLT_PRISM_HEADER: data += 144; goto ieee802_11; ieee802_11: case FAKE_DLT_IEEE802_11: if (data + 24 <= end_data && (data[0] & WIFI_FC0_TYPE_MASK) == WIFI_FC0_TYPE_DATA) { data += ((data[1] & 0x03) == 0x03 ? 30 : 24); goto rfc1483; } break; case FAKE_DLT_NULL: { if (data + 4 > end_data) break; int family = data[0] | (data[1] << 8); if (family == 0) family = (data[2] << 8) | data[3]; if (family == 2 /* BSD_AF_INET */ || family == 24 /* BSD_AF_INET6_BSD */ || family == 28 /* BSD_AF_INET6_FREEBSD */ || family == 30 /* BSD_AF_INET6_DARWIN */) iph = reinterpret_cast<const click_ip*>(data + 4); break; } default: break; } if (!iph) return false;#if !HAVE_INDIFFERENT_ALIGNMENT // Machine may crash if we try to access 'iph'. Align it on a word // boundary. uintptr_t header_ptr = reinterpret_cast<uintptr_t>(iph); if (header_ptr & 3) { int header_off = header_ptr - reinterpret_cast<uintptr_t>(p->data()); if (Packet *q = p->shift_data(-(header_ptr & 3), false)) { p = q; iph = reinterpret_cast<const click_ip *>(q->data() + header_off); } else // cannot align; return it as a non-IP packet return false; }#endif if (iph->ip_v == 4) { if (iph->ip_hl >= 5 && reinterpret_cast<const uint8_t*>(iph) + (iph->ip_hl << 2) <= end_data) { p->set_ip_header(iph, iph->ip_hl << 2); p->set_dst_ip_anno(iph->ip_dst); return true; } } else if (iph->ip_v == 6) { if (reinterpret_cast<const uint8_t*>(iph) + sizeof(click_ip6) <= end_data) { p->set_ip6_header(reinterpret_cast<const click_ip6*>(iph)); return true; } } return false;}CLICK_ENDDECLSELEMENT_REQUIRES(userlevel|ns)ELEMENT_PROVIDES(FakePcap)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -