From c72d191ab5c960be94c9f516aa94ec214f54b0c7 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Mon, 20 Jul 2015 11:45:28 -0700 Subject: [PATCH] Refactoring L2 parsing code to reside in the Packet class. That way it can be reused more easily. This also avoid having to change the serialization structure for packets, which is a problem as external sources of packets (via Broccoli) wouldn't have the new attributes available to send. Also moving Packet.{h,cc} and Layer2.{h,cc} into iosource/, and removing header size from properties that packet sources have to provide, as we can now compute that easily from the link type. Plus some more cleanup. --- CHANGES | 8 + VERSION | 4 + src/CMakeLists.txt | 1 - src/Packet.h | 106 ------- src/RemoteSerializer.cc | 2 +- src/Serializer.cc | 12 +- src/Sessions.cc | 12 +- src/Sessions.h | 4 - src/analyzer/protocol/arp/ARP.h | 3 +- src/bro.bif | 2 +- src/event.bif | 12 +- src/iosource/CMakeLists.txt | 2 + src/iosource/PktSrc.cc | 284 +----------------- src/iosource/PktSrc.h | 23 -- src/iosource/pcap/Dumper.cc | 2 +- src/iosource/pcap/Source.cc | 2 +- .../btest/plugins/pktsrc-plugin/src/Foo.cc | 1 - 17 files changed, 43 insertions(+), 437 deletions(-) delete mode 100644 src/Packet.h diff --git a/CHANGES b/CHANGES index aefe5d7929..7902f9ea7f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,12 @@ +<<<<<<< HEAD +======= +2.4-39 | 2015-07-20 15:30:35 -0700 + + * Refactoring layer 2 parsing code to reside in the Packet class, + plus further layer 2 cleanup. (Robin Sommer) + +>>>>>>> c7602ac... Cleanup 2.4-32 | 2015-07-16 17:21:29 -0700 * Refactor code to use a common Packet type throught. (Jeff Barber) diff --git a/VERSION b/VERSION index 1116eda970..c281ab1728 100644 --- a/VERSION +++ b/VERSION @@ -1 +1,5 @@ +<<<<<<< HEAD 2.4-32 +======= +2.4-39 +>>>>>>> c7602ac... Cleanup diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7f28d5d695..bdbd3839ce 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -297,7 +297,6 @@ set(bro_SRCS IntSet.cc IP.cc IPAddr.cc - Layer2.cc List.cc Reporter.cc NFA.cc diff --git a/src/Packet.h b/src/Packet.h deleted file mode 100644 index f1dd233be5..0000000000 --- a/src/Packet.h +++ /dev/null @@ -1,106 +0,0 @@ -#ifndef packet_h -#define packet_h - -#include "Desc.h" -#include "IP.h" -#include "NetVar.h" - -enum Layer3Proto { - L3_UNKNOWN = -1, - L3_IPV4 = 1, - L3_IPV6 = 2, - L3_ARP = 3, -}; - -// A link-layer packet. -// -// Note that for serialization we don't use much of the support provided by -// the serialization framework. Serialize/Unserialize do all the work by -// themselves. In particular, Packets aren't derived from SerialObj. They are -// completely seperate and self-contained entities, and we don't need any of -// the sophisticated features like object caching. - -class Packet { -public: - Packet() - { - struct timeval ts = {0, 0}; - Init(0, &ts, 0, 0, 0); - } - // Construct and initialize from packet data. - // - // arg_free: If true makes an internal copy of the *data*. If false, - // stores just a pointer to *data*, which must remain valid. - Packet(int arg_link_type, struct timeval *arg_ts, uint32 arg_caplen, - uint32 arg_len, const u_char *arg_data, int arg_free = false, - std::string arg_tag = std::string(""), uint32 arg_hdrsize = 0, - Layer3Proto arg_l3_proto = L3_UNKNOWN) - { - Init(arg_link_type, arg_ts, arg_caplen, arg_len, arg_data, arg_free, arg_tag, - arg_hdrsize, arg_l3_proto); - } - - ~Packet() - { - if ( free ) - delete [] data; - } - - // Initialize with data from pointer. - // - // arg_free: If true makes an internal copy of the *data*. If false, - // stores just a pointer to *data*, which must remain valid. - void Init(int arg_link_type, struct timeval *arg_ts, uint32 arg_caplen, - uint32 arg_len, const u_char *arg_data, int arg_free = false, - std::string arg_tag = std::string(""), uint32 arg_hdrsize = 0, - Layer3Proto arg_l3_proto = L3_UNKNOWN) - { - link_type = arg_link_type; - ts = *arg_ts; - cap_len = arg_caplen; - len = arg_len; - free = arg_free; - - if ( free ) - { - data = new u_char[cap_len]; - memcpy(const_cast(data), arg_data, cap_len); - } - else - data = arg_data; - - hdr_size = arg_hdrsize; - l3_proto = arg_l3_proto; - tag = arg_tag; - time = ts.tv_sec + double(ts.tv_usec) / 1e6; - eth_type = 0; - vlan = 0; - } - - const IP_Hdr IP() const - { return IP_Hdr((struct ip *) (data + hdr_size), false); } - - void Describe(ODesc* d) const; - - bool Serialize(SerialInfo* info) const; - static Packet* Unserialize(UnserialInfo* info); - - std::string tag; /// Used in serialization - double time; /// Timestamp reconstituted as float - - struct timeval ts; /// Capture timestamp - const u_char* data; /// Packet data. - uint32 link_type; /// pcap link_type (DLT_EN10MB, DLT_RAW, etc) - uint32 cap_len; /// Captured packet length - uint32 len; /// Actual length on wire - uint32 hdr_size; /// Layer 2 header size - Layer3Proto l3_proto; /// Layer 3 protocol identified (if any) - uint32 eth_type; /// If L2==ethernet, innermost ethertype field - uint32 vlan; /// (Outermost) VLan tag if any, else 0 - -private: - // should we delete associated packet memory upon destruction. - bool free; -}; - -#endif // packet_h diff --git a/src/RemoteSerializer.cc b/src/RemoteSerializer.cc index 3c0dec4f20..44ec678a0f 100644 --- a/src/RemoteSerializer.cc +++ b/src/RemoteSerializer.cc @@ -200,7 +200,7 @@ extern "C" { // Gets incremented each time there's an incompatible change // to the communication internals. -static const unsigned short PROTOCOL_VERSION = 0x08; +static const unsigned short PROTOCOL_VERSION = 0x07; static const char MSG_NONE = 0x00; static const char MSG_VERSION = 0x01; diff --git a/src/Serializer.cc b/src/Serializer.cc index d45e572611..554e8b36b6 100644 --- a/src/Serializer.cc +++ b/src/Serializer.cc @@ -1136,9 +1136,7 @@ bool Packet::Serialize(SerialInfo* info) const return SERIALIZE(uint32(ts.tv_sec)) && SERIALIZE(uint32(ts.tv_usec)) && SERIALIZE(uint32(len)) && - SERIALIZE(uint32(link_type)) && - SERIALIZE(uint32(hdr_size)) && - SERIALIZE(uint32(l3_proto)) && + SERIALIZE(link_type) && info->s->Write(tag.c_str(), tag.length(), "tag") && info->s->Write((const char*)data, cap_len, "data"); } @@ -1152,14 +1150,12 @@ static iosource::PktDumper* dump = 0; Packet* Packet::Unserialize(UnserialInfo* info) { struct timeval ts; - uint32 len, link_type, hdr_size, l3_proto; + uint32 len, link_type; if ( ! (UNSERIALIZE((uint32 *)&ts.tv_sec) && UNSERIALIZE((uint32 *)&ts.tv_usec) && UNSERIALIZE(&len) && - UNSERIALIZE(&link_type) && - UNSERIALIZE(&hdr_size) && - UNSERIALIZE(&l3_proto)) ) + UNSERIALIZE(&link_type)) ) return 0; char* tag; @@ -1175,7 +1171,7 @@ Packet* Packet::Unserialize(UnserialInfo* info) } Packet *p = new Packet(link_type, &ts, caplen, len, pkt, true, - std::string(tag), hdr_size, (Layer3Proto) l3_proto); + std::string(tag)); delete [] tag; // For the global timer manager, we take the global network_time as the diff --git a/src/Sessions.cc b/src/Sessions.cc index db1944634a..19f4f6104f 100644 --- a/src/Sessions.cc +++ b/src/Sessions.cc @@ -15,7 +15,7 @@ #include "Sessions.h" #include "Reporter.h" #include "OSFinger.h" -#include "Layer2.h" +#include "iosource/Layer2.h" #include "analyzer/protocol/icmp/ICMP.h" #include "analyzer/protocol/udp/UDP.h" @@ -169,11 +169,8 @@ void NetSessions::Done() void NetSessions::DispatchPacket(double t, const Packet* pkt, iosource::PktSrc* src_ps) { - NextPacket(t, pkt); - } + SegmentProfiler(segment_logger, "dispatching-packet"); -void NetSessions::NextPacket(double t, const Packet* pkt) - { if ( raw_packet ) { val_list* vl = new val_list(); @@ -185,9 +182,6 @@ void NetSessions::NextPacket(double t, const Packet* pkt) ProcNextPacket(t, pkt); } -void NetSessions::ProcNextPacket(double t, const Packet *pkt) - { - SegmentProfiler(segment_logger, "processing-packet"); if ( pkt_profiler ) pkt_profiler->ProfilePkt(t, pkt->cap_len); @@ -804,7 +798,7 @@ void NetSessions::DoNextInnerPacket(double t, const Packet* pkt, // Construct fake packet for DoNextPacket Packet p; - p.Init(DLT_RAW, &ts, caplen, len, data, false, "", 0, l3_proto); + p.Init(DLT_RAW, &ts, caplen, len, data, false, ""); DoNextPacket(t, &p, inner, outer); delete inner; diff --git a/src/Sessions.h b/src/Sessions.h index 51539c42ef..6561b555e7 100644 --- a/src/Sessions.h +++ b/src/Sessions.h @@ -214,10 +214,6 @@ protected: TransportProto transport_proto, uint8 tcp_flags, bool& flip_roles); - void NextPacket(double t, const Packet* pkt); - - void ProcNextPacket(double t, const Packet *pkt); - // Record the given packet (if a dumper is active). If len=0 // then the whole packet is recorded, otherwise just the first // len bytes. diff --git a/src/analyzer/protocol/arp/ARP.h b/src/analyzer/protocol/arp/ARP.h index d0b035ef24..1778f5e200 100644 --- a/src/analyzer/protocol/arp/ARP.h +++ b/src/analyzer/protocol/arp/ARP.h @@ -24,7 +24,8 @@ #endif #include "NetVar.h" -#include "Packet.h" + +class Packet; extern "C" { #include diff --git a/src/bro.bif b/src/bro.bif index 9d3a2c42a8..629abe7735 100644 --- a/src/bro.bif +++ b/src/bro.bif @@ -20,9 +20,9 @@ #include "Reporter.h" #include "IPAddr.h" #include "util.h" -#include "Packet.h" #include "file_analysis/Manager.h" #include "iosource/Manager.h" +#include "iosource/Packet.h" using namespace std; diff --git a/src/event.bif b/src/event.bif index 7ba6fc2e1e..456de20b3a 100644 --- a/src/event.bif +++ b/src/event.bif @@ -225,21 +225,21 @@ event udp_session_done%(u: connection%); ## ``ANALYZER_*`` constants right now. event scheduled_analyzer_applied%(c: connection, a: Analyzer::Tag%); -## Generated for every packet Bro sees that has a valid link-layer header. This +## Generated for every packet Bro sees that have a valid link-layer header. This ## is a very very low-level and expensive event that should be avoided when at all ## possible. It's usually infeasible to handle when processing even medium volumes ## of traffic in real-time. That said, if you work from a trace and want to do some -## packet-level analysis, it may come in handy. +## packet-level analysis, it may come in handy. ## ## p: Information from the header of the packet that triggered the event. ## ## .. bro:see:: new_packet packet_contents event raw_packet%(p: raw_pkt_hdr%); -## Generated for all packets that make it into Bro's connection processing . In -## contrast to :bro:id:`raw_packet` this filters out some packets that, e.g., don't -## pass certain sanity checks. -## +## Generated for all packets that make it into Bro's connection processing. In +## contrast to :bro:id:`raw_packet` this filters out some more packets that don't +## pass certain sanity checks. +## ## This is a very low-level and expensive event that should be avoided when at all ## possible. It's usually infeasible to handle when processing even medium volumes ## of traffic in real-time. That said, if you work from a trace and want to do some diff --git a/src/iosource/CMakeLists.txt b/src/iosource/CMakeLists.txt index a36667aee7..b08e62334a 100644 --- a/src/iosource/CMakeLists.txt +++ b/src/iosource/CMakeLists.txt @@ -11,7 +11,9 @@ add_subdirectory(pcap) set(iosource_SRCS BPF_Program.cc Component.cc + Layer2.cc Manager.cc + Packet.cc PktDumper.cc PktSrc.cc ) diff --git a/src/iosource/PktSrc.cc b/src/iosource/PktSrc.cc index e22f8da6dd..8012f79f1b 100644 --- a/src/iosource/PktSrc.cc +++ b/src/iosource/PktSrc.cc @@ -17,7 +17,6 @@ PktSrc::Properties::Properties() { selectable_fd = -1; link_type = -1; - hdr_size = -1; netmask = NETMASK_UNKNOWN; is_live = false; } @@ -67,11 +66,6 @@ bool PktSrc::IsError() const return ErrorMsg(); } -int PktSrc::HdrSize() const - { - return IsOpen() ? props.hdr_size : -1; - } - int PktSrc::SnapLen() const { return snaplen; // That's a global. Change? @@ -98,7 +92,7 @@ double PktSrc::CurrentPacketWallClock() void PktSrc::Opened(const Properties& arg_props) { - if ( arg_props.hdr_size < 0 ) + if ( Packet::GetLinkHeaderSize(arg_props.link_type) < 0 ) { char buf[512]; safe_snprintf(buf, sizeof(buf), @@ -160,33 +154,6 @@ void PktSrc::ContinueAfterSuspend() current_wallclock = current_time(true); } -int PktSrc::GetLinkHeaderSize(int link_type) - { - switch ( link_type ) { - case DLT_NULL: - return 4; - - case DLT_EN10MB: - return 14; - - case DLT_FDDI: - return 13 + 8; // fddi_header + LLC - -#ifdef DLT_LINUX_SLL - case DLT_LINUX_SLL: - return 16; -#endif - - case DLT_PPP_SERIAL: // PPP_SERIAL - return 4; - - case DLT_RAW: - return 0; - } - - return -1; - } - double PktSrc::CheckPseudoTime() { if ( ! IsOpen() ) @@ -284,249 +251,20 @@ void PktSrc::Process() if ( ! ExtractNextPacketInternal() ) return; - // Unfortunately some packets on the link might have MPLS labels - // while others don't. That means we need to ask the link-layer if - // labels are in place. - bool have_mpls = false; - - Layer3Proto l3_proto = L3_UNKNOWN; - const u_char* data = current_packet.data; - - current_packet.link_type = props.link_type; - - switch ( props.link_type ) { - case DLT_NULL: + if ( current_packet.Layer2Valid() ) { - int protocol = (data[3] << 24) + (data[2] << 16) + (data[1] << 8) + data[0]; - data += GetLinkHeaderSize(props.link_type); + if ( pseudo_realtime ) + { + current_pseudo = CheckPseudoTime(); + net_packet_dispatch(current_pseudo, ¤t_packet, this); + if ( ! first_wallclock ) + first_wallclock = current_time(true); + } - // From the Wireshark Wiki: "AF_INET6, unfortunately, has - // different values in {NetBSD,OpenBSD,BSD/OS}, - // {FreeBSD,DragonFlyBSD}, and {Darwin/Mac OS X}, so an IPv6 - // packet might have a link-layer header with 24, 28, or 30 - // as the AF_ value." As we may be reading traces captured on - // platforms other than what we're running on, we accept them - // all here. - - if ( protocol == AF_INET ) - l3_proto = L3_IPV4; - else if ( protocol == 24 || protocol == 28 || protocol == 30 ) - l3_proto = L3_IPV6; else - { - Weird("non_ip_packet_in_null_transport", ¤t_packet); - goto done; - } - - break; + net_packet_dispatch(current_packet.time, ¤t_packet, this); } - case DLT_EN10MB: - { - // Get protocol being carried from the ethernet frame. - int protocol = (data[12] << 8) + data[13]; - data += GetLinkHeaderSize(props.link_type); - current_packet.eth_type = protocol; - - switch ( protocol ) - { - // MPLS carried over the ethernet frame. - case 0x8847: - have_mpls = true; - break; - - // VLAN carried over the ethernet frame. - // 802.1q / 802.1ad - case 0x8100: - case 0x9100: - current_packet.vlan = ((data[0] << 8) + data[1]) & 0xfff; - protocol = ((data[2] << 8) + data[3]); - data += 4; // Skip the vlan header - - // Check for MPLS in VLAN. - if ( protocol == 0x8847 ) - { - have_mpls = true; - break; - } - - // Check for double-tagged (802.1ad) - if ( protocol == 0x8100 || protocol == 0x9100 ) - { - protocol = ((data[2] << 8) + data[3]); - data += 4; // Skip the vlan header - } - - current_packet.eth_type = protocol; - break; - - // PPPoE carried over the ethernet frame. - case 0x8864: - protocol = (data[6] << 8) + data[7]; - data += 8; // Skip the PPPoE session and PPP header - - if ( protocol == 0x0021 ) - l3_proto = L3_IPV4; - else if ( protocol == 0x0057 ) - l3_proto = L3_IPV6; - else - { - // Neither IPv4 nor IPv6. - Weird("non_ip_packet_in_pppoe_encapsulation", ¤t_packet); - goto done; - } - - break; - } - - // Normal path to determine Layer 3 protocol. - if ( ! have_mpls && l3_proto == L3_UNKNOWN ) - { - if ( protocol == 0x800 ) - l3_proto = L3_IPV4; - else if ( protocol == 0x86dd ) - l3_proto = L3_IPV6; - else if ( protocol == 0x0806 || protocol == 0x8035 ) - l3_proto = L3_ARP; - else - { - // Neither IPv4 nor IPv6. - Weird("non_ip_packet_in_ethernet", ¤t_packet); - goto done; - } - } - - break; - } - - case DLT_PPP_SERIAL: - { - // Get PPP protocol. - int protocol = (data[2] << 8) + data[3]; - data += GetLinkHeaderSize(props.link_type); - - if ( protocol == 0x0281 ) - { - // MPLS Unicast. Remove the data link layer and - // denote a header size of zero before the IP header. - have_mpls = true; - } - else if ( protocol == 0x0021 ) - l3_proto = L3_IPV4; - else if ( protocol == 0x0057 ) - l3_proto = L3_IPV6; - else - { - // Neither IPv4 nor IPv6. - Weird("non_ip_packet_in_ppp_encapsulation", ¤t_packet); - goto done; - } - break; - } - - default: - { - // Assume we're pointing at IP. Just figure out which version. - data += GetLinkHeaderSize(props.link_type); - const struct ip* ip = (const struct ip *)data; - - if ( ip->ip_v == 4 ) - l3_proto = L3_IPV4; - else if ( ip->ip_v == 6 ) - l3_proto = L3_IPV6; - else - { - // Neither IPv4 nor IPv6. - Weird("non_ip_packet", ¤t_packet); - goto done; - } - - break; - } - } - - if ( have_mpls ) - { - // Skip the MPLS label stack. - bool end_of_stack = false; - - while ( ! end_of_stack ) - { - end_of_stack = *(data + 2) & 0x01; - data += 4; - - if ( data >= current_packet.data + current_packet.cap_len ) - { - Weird("no_mpls_payload", ¤t_packet); - goto done; - } - } - - // We assume that what remains is IP - if ( data + sizeof(struct ip) >= current_packet.data + current_packet.cap_len ) - { - Weird("no_ip_in_mpls_payload", ¤t_packet); - goto done; - } - - const struct ip* ip = (const struct ip *)data; - - if ( ip->ip_v == 4 ) - l3_proto = L3_IPV4; - else if ( ip->ip_v == 6 ) - l3_proto = L3_IPV6; - else - { - // Neither IPv4 nor IPv6. - Weird("no_ip_in_mpls_payload", ¤t_packet); - goto done; - } - } - - else if ( encap_hdr_size ) - { - // Blanket encapsulation. We assume that what remains is IP. - data += encap_hdr_size; - if ( data + sizeof(struct ip) >= current_packet.data + current_packet.cap_len ) - { - Weird("no_ip_left_after_encap", ¤t_packet); - goto done; - } - - const struct ip* ip = (const struct ip *)data; - - if ( ip->ip_v == 4 ) - l3_proto = L3_IPV4; - else if ( ip->ip_v == 6 ) - l3_proto = L3_IPV6; - else - { - // Neither IPv4 nor IPv6. - Weird("no_ip_in_encap", ¤t_packet); - goto done; - } - - } - - // We've now determined (a) L3_IPV4 vs (b) L3_IPV6 vs - // (c) L3_ARP vs (d) L3_UNKNOWN (0 == anything else) - current_packet.l3_proto = l3_proto; - - // Calculate how much header we've used up. - current_packet.hdr_size = (data - current_packet.data); - - if ( pseudo_realtime ) - { - current_pseudo = CheckPseudoTime(); - net_packet_dispatch(current_pseudo, ¤t_packet, this); - if ( ! first_wallclock ) - first_wallclock = current_time(true); - } - - else - net_packet_dispatch(current_packet.time, ¤t_packet, this); - -done: have_packet = 0; DoneWithPacket(); } @@ -556,8 +294,6 @@ bool PktSrc::ExtractNextPacketInternal() if ( ExtractNextPacket(¤t_packet) ) { - current_packet.l3_proto = L3_UNKNOWN; - if ( ! first_timestamp ) first_timestamp = current_packet.time; diff --git a/src/iosource/PktSrc.h b/src/iosource/PktSrc.h index 0f20bb3a0a..bf4c811dca 100644 --- a/src/iosource/PktSrc.h +++ b/src/iosource/PktSrc.h @@ -215,22 +215,6 @@ public: */ virtual void Statistics(Stats* stats) = 0; - /** - * Helper method to return the header size for a given link tyoe. - * - * @param link_type The link tyoe. - * - * @return The header size in bytes. - */ - static int GetLinkHeaderSize(int link_type); - - /** - * Return the pcap link encapsulation type we started with. - * - * @return DLT_EN10MB (etc.) - */ - int GetLinkEncap(void); - protected: friend class Manager; @@ -258,13 +242,6 @@ protected: */ int link_type; - /** - * The size of the link-layer header for packets from this - * source. \a GetLinkHeaderSize() may be used to derive this - * value. - */ - int hdr_size; - /** * Returns the netmask associated with the source, or \c * NETMASK_UNKNOWN if unknown. diff --git a/src/iosource/pcap/Dumper.cc b/src/iosource/pcap/Dumper.cc index e6909f32b1..5bea6231f7 100644 --- a/src/iosource/pcap/Dumper.cc +++ b/src/iosource/pcap/Dumper.cc @@ -79,7 +79,7 @@ void PcapDumper::Open() } props.open_time = network_time; - props.hdr_size = PktSrc::GetLinkHeaderSize(pcap_datalink(pd)); + props.hdr_size = Packet::GetLinkHeaderSize(pcap_datalink(pd)); Opened(props); } diff --git a/src/iosource/pcap/Source.cc b/src/iosource/pcap/Source.cc index 45e8c89298..bebe02c018 100644 --- a/src/iosource/pcap/Source.cc +++ b/src/iosource/pcap/Source.cc @@ -5,6 +5,7 @@ #include "config.h" #include "Source.h" +#include "iosource/Packet.h" #ifdef HAVE_PCAP_INT_H #include @@ -274,7 +275,6 @@ void PcapSource::SetHdrSize() char errbuf[PCAP_ERRBUF_SIZE]; props.link_type = pcap_datalink(pd); - props.hdr_size = GetLinkHeaderSize(props.link_type); } iosource::PktSrc* PcapSource::Instantiate(const std::string& path, bool is_live) diff --git a/testing/btest/plugins/pktsrc-plugin/src/Foo.cc b/testing/btest/plugins/pktsrc-plugin/src/Foo.cc index afd5621d0f..af752a20bf 100644 --- a/testing/btest/plugins/pktsrc-plugin/src/Foo.cc +++ b/testing/btest/plugins/pktsrc-plugin/src/Foo.cc @@ -17,7 +17,6 @@ Foo::Foo(const std::string& path, bool is_live) props.path = path; props.selectable_fd = open("/bin/sh", O_RDONLY); // any fd is fine. props.link_type = DLT_RAW; - props.hdr_size = 0; props.netmask = 0; props.is_live = 0; }