"Fossies" - the Fresh Open Source Software Archive

Member "tcpflow-1.6.1/src/datalink.cpp" (19 Feb 2021, 9272 Bytes) of package /linux/misc/tcpflow-1.6.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "datalink.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.5.0_vs_1.6.1.

    1 /**
    2  *
    3  * This file is part of tcpflow. Originally by Jeremy Elson
    4  * <jelson@circlemud.org>, rewritten by Simson Garfinkel.
    5  *
    6  * Initial Release: 7 April 1999.
    7  *
    8  * This source code is under the GNU Public License (GPL).  See
    9  * COPYING for details.
   10  *
   11  * This file contains datalink handlers which are called by the pcap callback.
   12  * The purpose of each handler is to make a packet_info() object and then call
   13  * process_packet. The packet_info() object contains both the original
   14  * MAC-layer (with some of the fields broken out) and the packet data layer.
   15  *
   16  * For wifi datalink handlers, please see datalink_wifi.cpp
   17  */
   18 
   19 #include <stddef.h>
   20 #include "tcpflow.h"
   21 
   22 /* The DLT_NULL packet header is 4 bytes long. It contains a network
   23  * order 32 bit integer that specifies the family, e.g. AF_INET.
   24  * DLT_NULL is used by the localhost interface.
   25  */
   26 #define NULL_HDRLEN 4
   27 
   28 /* Some systems hasn't defined ETHERTYPE_IPV6 */
   29 #ifndef ETHERTYPE_IPV6
   30 # define ETHERTYPE_IPV6 0x86DD
   31 #endif
   32 
   33 #ifndef ETH_P_QINQ1
   34 # define ETH_P_QINQ1    0x9100      /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
   35 #endif
   36 
   37 #ifndef ETH_P_8021AD
   38 # define ETH_P_8021AD   0x88A8          /* 802.1ad Service VLAN     */
   39 #endif
   40 
   41 
   42 int32_t datalink_tdelta = 0;
   43 
   44 #pragma GCC diagnostic ignored "-Wcast-align"
   45 void dl_null(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
   46 {
   47     u_int caplen = h->caplen;
   48     u_int length = h->len;
   49     uint32_t family = (uint32_t)*p;
   50 
   51     if (length != caplen) {
   52     DEBUG(6) ("warning: only captured %d bytes of %d byte null frame",
   53           caplen, length);
   54     }
   55 
   56     if (caplen < NULL_HDRLEN) {
   57     DEBUG(6) ("warning: received incomplete null frame");
   58     return;
   59     }
   60 
   61     /* make sure this is AF_INET */
   62     if (family != AF_INET && family != AF_INET6) {
   63     DEBUG(6)("warning: received null frame with unknown type (type 0x%x) (AF_INET=%x; AF_INET6=%x)",
   64          family,AF_INET,AF_INET6);
   65     return;
   66     }
   67     struct timeval tv;
   68     be13::packet_info pi(DLT_NULL,h,p,tvshift(tv,h->ts),p+NULL_HDRLEN,caplen - NULL_HDRLEN);
   69     be13::plugin::process_packet(pi);
   70 }
   71 #pragma GCC diagnostic warning "-Wcast-align"
   72 
   73 static uint64_t counter=0;
   74 /* DLT_RAW: just a raw IP packet, no encapsulation or link-layer
   75  * headers.  Used for PPP connections under some OSs including Linux
   76  * and IRIX. */
   77 void dl_raw(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
   78 {
   79     if (h->caplen != h->len) {
   80     DEBUG(6) ("warning: only captured %d bytes of %d byte raw frame",
   81           h->caplen, h->len);
   82     }
   83     struct timeval tv;
   84     be13::packet_info pi(DLT_RAW,h,p,tvshift(tv,h->ts),p, h->caplen);
   85     counter++;
   86     be13::plugin::process_packet(pi);
   87 }
   88 
   89 /* Ethernet datalink handler; used by all 10 and 100 mbit/sec
   90  * ethernet.  We are given the entire ethernet header so we check to
   91  * make sure it's marked as being IP.
   92  */
   93 #pragma GCC diagnostic ignored "-Wcast-align"
   94 void dl_ethernet(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
   95 {
   96     u_int caplen = h->caplen;
   97     u_int length = h->len;
   98     struct be13::ether_header *eth_header = (struct be13::ether_header *) p;
   99     u_int ether_type_offset = offsetof(struct be13::ether_header, ether_type);
  100 
  101     /* Variables to support VLAN */
  102     const u_short *ether_type = NULL;
  103     const u_char *ether_data = NULL;
  104 
  105     if (caplen < ether_type_offset) {
  106         DEBUG(0) ("error: the captured packet header bytes are shorter than the ether_type offset");
  107         return;
  108     }
  109 
  110     ether_type = &eth_header->ether_type; /* where the ether type is located */
  111     ether_data = p+sizeof(struct be13::ether_header); /* where the data is located */
  112 
  113     if (length != caplen) {
  114     DEBUG(6) ("warning: only captured %d bytes of %d byte ether frame",
  115           caplen, length);
  116     }
  117 
  118     /* Handle basic VLAN packets */
  119     while (ntohs(*ether_type) == ETHERTYPE_VLAN
  120 #ifdef ETH_P_QINQ1
  121            || ntohs(*ether_type) == ETH_P_QINQ1
  122 #endif
  123 #ifdef ETH_P_8021AD
  124            || ntohs(*ether_type) == ETH_P_8021AD
  125 #endif
  126            ) {
  127     //vlan = ntohs(*(u_short *)(p+sizeof(struct ether_header)));
  128     ether_type += 2;            /* skip past VLAN header (note it skips by 2s) */
  129     ether_data += 4;            /* skip past VLAN header */
  130     caplen     -= 4;
  131         if (caplen < ether_type_offset) {
  132             DEBUG(0) ("error: the captured packet header bytes are shorter than the ether_type offset");
  133             return;
  134         }
  135     }
  136 
  137     if (caplen < sizeof(struct be13::ether_header)) {
  138     DEBUG(6) ("warning: received incomplete ethernet frame");
  139     return;
  140     }
  141 
  142     /* Create a packet_info structure with ip data and data length  */
  143     try {
  144         struct timeval tv;
  145         be13::packet_info pi(DLT_IEEE802,h,p,tvshift(tv,h->ts),
  146                              ether_data, caplen - sizeof(struct be13::ether_header));
  147         switch (ntohs(*ether_type)){
  148         case ETHERTYPE_IP:
  149         case ETHERTYPE_IPV6:
  150             be13::plugin::process_packet(pi);
  151             break;
  152 
  153 #ifdef ETHERTYPE_ARP
  154         case ETHERTYPE_ARP:
  155             /* What should we do for ARP? */
  156             break;
  157 #endif
  158 #ifdef ETHERTYPE_LOOPBACK
  159         case ETHERTYPE_LOOPBACK:
  160             /* What do do for loopback? */
  161             break;
  162 #endif
  163 #ifdef ETHERTYPE_REVARP
  164         case ETHERTYPE_REVARP:
  165             /* What to do for REVARP? */
  166             break;
  167 #endif
  168         default:
  169             /* Unknown Ethernet Frame Type */
  170             DEBUG(6) ("warning: received ethernet frame with unknown type 0x%x", ntohs(eth_header->ether_type));
  171             break;
  172         }
  173     } catch( std::logic_error e){
  174         std::string s(std::string("warning: caught std::logic_error ")
  175                       + e.what()
  176                       + std::string(" in packet"));
  177         DEBUG(6)(s.c_str());
  178     }
  179 }
  180 
  181 #pragma GCC diagnostic warning "-Wcast-align"
  182 
  183 /* The DLT_PPP packet header is 4 bytes long.  We just move past it
  184  * without parsing it.  It is used for PPP on some OSs (DLT_RAW is
  185  * used by others; see below)
  186  */
  187 #define PPP_HDRLEN 4
  188 
  189 void dl_ppp(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
  190 {
  191     u_int caplen = h->caplen;
  192     u_int length = h->len;
  193 
  194     if (length != caplen) {
  195     DEBUG(6) ("warning: only captured %d bytes of %d byte PPP frame",
  196           caplen, length);
  197     }
  198 
  199     if (caplen < PPP_HDRLEN) {
  200     DEBUG(6) ("warning: received incomplete PPP frame");
  201     return;
  202     }
  203 
  204     struct timeval tv;
  205     be13::packet_info pi(DLT_PPP,h,p,tvshift(tv,h->ts),p + PPP_HDRLEN, caplen - PPP_HDRLEN);
  206     be13::plugin::process_packet(pi);
  207 }
  208 
  209 
  210 #ifdef DLT_LINUX_SLL
  211 #define SLL_HDR_LEN       16
  212 
  213 #define SLL_ADDRLEN 8
  214 
  215 #ifndef ETHERTYPE_MPLS
  216 #define ETHERTYPE_MPLS      0x8847
  217 #endif
  218 #ifndef ETHERTYPE_MPLS_MULTI
  219 #define ETHERTYPE_MPLS_MULTI    0x8848
  220 #endif
  221 
  222 #pragma GCC diagnostic ignored "-Wcast-align"
  223 void dl_linux_sll(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
  224 {
  225     u_int caplen = h->caplen;
  226     u_int length = h->len;
  227 
  228     if (length != caplen) {
  229     DEBUG(6) ("warning: only captured %d bytes of %d byte Linux cooked frame",
  230           caplen, length);
  231     }
  232 
  233     if (caplen < SLL_HDR_LEN) {
  234     DEBUG(6) ("warning: received incomplete Linux cooked frame");
  235     return;
  236     }
  237 
  238     struct _sll_header {
  239         u_int16_t   sll_pkttype;    /* packet type */
  240         u_int16_t   sll_hatype; /* link-layer address type */
  241         u_int16_t   sll_halen;  /* link-layer address length */
  242         u_int8_t    sll_addr[SLL_ADDRLEN];  /* link-layer address */
  243         u_int16_t   sll_protocol;   /* protocol */
  244     };
  245 
  246     _sll_header *sllp = (_sll_header*)p;
  247     u_int mpls_sz = 0;
  248     if (ntohs(sllp->sll_protocol) == ETHERTYPE_MPLS) {
  249         // unwind MPLS stack
  250         do {
  251             if(caplen < SLL_HDR_LEN + mpls_sz + 4){
  252                 DEBUG(6) ("warning: MPLS stack overrun");
  253                 return;
  254             }
  255             mpls_sz += 4;
  256             caplen -= 4;
  257         } while ((p[SLL_HDR_LEN + mpls_sz - 2] & 1) == 0 );
  258     }
  259 
  260     struct timeval tv;
  261     be13::packet_info pi(DLT_LINUX_SLL,h,p,tvshift(tv,h->ts),p + SLL_HDR_LEN + mpls_sz, caplen - SLL_HDR_LEN);
  262     be13::plugin::process_packet(pi);
  263 }
  264 #endif
  265 
  266 #ifndef DLT_IEEE802_11_RADIO
  267 #define DLT_IEEE802_11_RADIO    127  /* 802.11 plus radiotap radio header */
  268 #endif
  269 
  270 /* List of callbacks for each data link type */
  271 dlt_handler_t handlers[] = {
  272     { dl_null,     DLT_NULL },
  273 /* Some systems define DLT_RAW as 12, some as 14, and some as 101.
  274  * So it is hard-coded here.
  275  */
  276     { dl_raw,      12 },
  277     { dl_raw,      14 },
  278     { dl_raw,     101 },
  279     { dl_ethernet, DLT_EN10MB },
  280     { dl_ethernet, DLT_IEEE802 },
  281     { dl_ppp,           DLT_PPP },
  282 #ifdef DLT_LINUX_SLL
  283     { dl_linux_sll,        DLT_LINUX_SLL },
  284 #endif
  285 #if defined(USE_WIFI) && !defined(WIN32)
  286     { dl_ieee802_11_radio, DLT_IEEE802_11 },
  287     { dl_ieee802_11_radio, DLT_IEEE802_11_RADIO },
  288     { dl_prism,            DLT_PRISM_HEADER},
  289 #endif
  290     { NULL, 0 }
  291 };
  292 
  293 pcap_handler find_handler(int datalink_type, const char *device)
  294 {
  295     int i;
  296 
  297     DEBUG(3) ("looking for handler for datalink type %d for interface %s",
  298           datalink_type, device);
  299 
  300     for (i = 0; handlers[i].handler != NULL; i++){
  301     if (handlers[i].type == datalink_type){
  302             return handlers[i].handler;
  303         }
  304     }
  305 
  306     die("sorry - unknown datalink type %d on interface %s", datalink_type, device);
  307     return NULL;    /* NOTREACHED */
  308 }