Logo Search packages:      
Sourcecode: netams version File versions  Download package

ds_libpcap.c

/*************************************************************************
***   Authentication, authorization, accounting + firewalling package
***   Copyright 1998-2002 Anton Vinokurov <anton@netams.com>
***   Copyright 2002-2008 NeTAMS Development Team
***   This code is GPL v3
***   For latest version and more info, visit this project web page
***   located at http://www.netams.com
***
*************************************************************************/
/* $Id: ds_libpcap.c,v 1.69 2009-07-21 14:52:59 jura Exp $ */

#ifndef NOPCAP

#include "netams.h"
#include "ds_any.h"
#include "ds_libpcap.h"
#ifdef PCAP_NEED_POLL
#include "pcap-int.h"
#endif
#include "flow.h"

//obtained from fprobe
struct DLT dlt[] = {
#ifdef DLT_NULL
        {DLT_NULL, 0, 4, 4, "NULL"},
#endif
#ifdef DLT_EN10MB
        {DLT_EN10MB, 12, 14, 17, "EN10MB"},
#endif
#ifdef DLT_IEEE802
        {DLT_IEEE802, 14, 22, 17, "IEEE802"},
#endif
#ifdef DLT_ARCNET
        {DLT_ARCNET, 2 , 6, 6, "ARCNET"},
#endif
#ifdef DLT_SLIP
        {DLT_SLIP, -1, 16, 16, "SLIP"},
#endif
#ifdef DLT_PPP
        {DLT_PPP, 2, 4, 4, "PPP"},
#endif
#ifdef DLT_FDDI
        /*
        FIXME
        See gencode.c from libpcap
        */
        {DLT_FDDI, 13, 21, 16, "FDDI"},
#endif
#ifdef DLT_ATM_RFC1483
        {DLT_ATM_RFC1483, 0, 8, 3, "ATM_RFC1483"},
#endif
#ifdef DLT_RAW
        {DLT_RAW, -1, 0, 0, "RAW"},
#endif
#ifdef DLT_SLIP_BSDOS
        {DLT_SLIP_BSDOS, -1, 24, 24, "SLIP_BSDOS"},
#endif
#ifdef DLT_PPP_BSDOS
        {DLT_PPP_BSDOS, 5, 24, 24, "PPP_BSDOS"},
#endif
#ifdef DLT_ATM_CLIP
        {DLT_ATM_CLIP, 0, 8, 3, "ATM_CLIP"},
#endif
#ifdef DLT_PPP_SERIAL
        {DLT_PPP_SERIAL, 2, 4, 4, "PPP_SERIAL"},
#endif
#ifdef DLT_PPP_ETHER
        {DLT_PPP_ETHER, 6, 8, 8, "PPP_ETHER"},
#endif
#ifdef DLT_C_HDLC
        {DLT_C_HDLC, 2, 4, 4, "C_HDLC"},
#endif
#ifdef DLT_IEEE802_11
        {DLT_IEEE802_11, 24, 32, 27, "IEEE802_11"},
#endif
#ifdef DLT_LOOP
        {DLT_LOOP, 0, 4, 4, "LOOP"},
#endif
#ifdef DLT_LINUX_SLL
        {DLT_LINUX_SLL, 14, 16, 16, "LINUX_SLL"},
#endif
#ifdef DLT_LTALK
        {DLT_LTALK, -1, 0, 0, "LTALK"},
#endif
#ifdef DLT_PRISM_HEADER
        {DLT_PRISM_HEADER, 144 + 24, 144 + 30, 144 + 27, "PRISM_HEADER"},
#endif
#ifdef DLT_IP_OVER_FC
        {DLT_IP_OVER_FC, 16, 24, 19, "IP_OVER_FC"},
#endif
#ifdef DLT_SUNATM
        {DLT_SUNATM, 4, 4 + 8, 4 + 3, "SUNATM"},
#endif
#ifdef DLT_ARCNET_LINUX
        {DLT_ARCNET_LINUX, 4, 8, 8, "ARCNET_LINUX"},
#endif
#ifdef DLT_ENC
        {DLT_ENC, 0, 12, 12, "ENC"},
#endif
#ifdef DLT_FRELAY
        {DLT_FRELAY, -1, 0, 0, "FRELAY"},
#endif
#ifdef DLT_IEEE802_11_RADIO
        {DLT_IEEE802_11_RADIO, 64 + 24, 64 + 32, 64 + 27, "IEEE802_11_RADIO"},
#endif
#ifdef DLT_PFLOG
        {DLT_PFLOG, 0, 28, 28, "PFLOG"},
#endif
#ifdef DLT_LINUX_IRDA
        {DLT_LINUX_IRDA, -1, -1, -1, "LINUX_IRDA"},
#endif
#ifdef DLT_APPLE_IP_OVER_IEEE1394
        {DLT_APPLE_IP_OVER_IEEE1394, 16, 18, 0, "APPLE_IP_OVER_IEEE1394"},
#endif
#ifdef DLT_IEEE802_11_RADIO_AVS
        {DLT_IEEE802_11_RADIO_AVS, 64 + 24, 64 + 32, 64 + 27, "IEEE802_11_RADIO_AVS"},
#endif
#ifdef DLT_PFSYNC
        {DLT_PFSYNC, -1, 4, 4, "PFSYNC"},
#endif
        {-1, -1, -1, -1, "UNKNOWN"}
};

void ds_libpcap_cancel(void *);
void pcap_callback(unsigned char *, const struct pcap_pkthdr *, const unsigned char *);
void ds_libpcap_stats(struct cli_def *cli, Service_DS *ds);


void ds_libpcap(Service_DS *ds) {
      u_char            i;

      ds->pcap_data= aMalloc(sizeof(struct captured_data));
      struct captured_data *cap_data=(struct captured_data *)ds->pcap_data;

      pcap_t                  *pcap;
      int                     snaplen = 70; //default size to capture
      struct bpf_program      pf;
      char              errbuf[PCAP_ERRBUF_SIZE];

      pthread_cleanup_push(ds_libpcap_cancel, (void *)&cap_data->pcap);
      pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);

INIT:

#ifdef LAYER7_DETECT
      if (ds->layer7_detect!=LAYER7_DETECT_NONE)
            snaplen = MAX_PKT_SIZE;
#endif

      while((pcap = pcap_open_live(ds->src_cmd, snaplen, (ds->ds_flags == DS_PROMISC), 1000, errbuf))==NULL){
            aLog(D_ERR, "failed to open pcap interface: %s\n", errbuf);
            ds->Sleep(10);
      }

      {
            bpf_u_int32 netp, maskp;
            if(pcap_lookupnet(ds->src_cmd, &netp, &maskp, errbuf) == -1) {
                  aLog(D_WARN, "%s\n", errbuf);
            }
      }

      cap_data->pcap = pcap;
#ifdef PCAP_NEED_POLL
      SET_POLL(pcap->fd);
#endif

      cap_data->datalink = pcap_datalink(pcap);
      for (i = 0;; i++)
            if (dlt[i].linktype == cap_data->datalink || dlt[i].linktype == -1) {
                  cap_data->offset = dlt[i].offset_nl;
                  cap_data->link_type_idx = i;
                  break;
            }

      aLog(D_INFO, "Libpcap %s %s: %s, capturing size %d\n", \
            ds->src_cmd, (ds->ds_flags&DS_PROMISC)?"promisc":"", dlt[i].descr, snaplen);

      if (ds->root && ds->root->rule_str) {
            if (-1 == pcap_compile(pcap, &pf, ds->root->rule_str, 1, 0)) {
                  aLog(D_ERR, "failed to compile pcap: %s\n", pcap_geterr(pcap));
                  return;
            }
            if (-1 == pcap_setfilter(pcap, &pf)) {
                  aLog(D_ERR, "failed to setfilter pcap: %s\n", pcap_geterr(pcap));
                  return;
            }
#ifndef NETBSD
            pcap_freecode(&pf);
#endif
      } else
            aLog(D_WARN, "no rule for pcap, capturing all \n");

      aLog(D_INFO, "Libpcap packet processing for data-source:%u initialized\n", ds->instance);

      int   status, k=0;
      struct      timeval start;

      while(1) {
#ifdef PCAP_NEED_POLL
            CHECK_POLL(ds,status);
            if(!status && k) {
                  netams_gettimeofday(&start, NULL);
                  ds->FE->Expiresearch(&start);
                  k=1;
                  continue;
            }
#else
            netams_gettimeofday(&start, NULL);
            ds->FE->Expiresearch(&start);
#endif

            status = pcap_dispatch(pcap, 1, pcap_callback, (unsigned char *)ds);
            if (status == -1) {
                  aLog(D_WARN, "pcap dispatch error: %s\n", pcap_geterr(pcap));
                  goto INIT;
            }
            k=1;
      }
      pthread_cleanup_pop(0);
      return;
}

void ds_libpcap_stats(struct cli_def *cli, Service_DS *ds) {
        if(!ds->pcap_data) return;

      struct captured_data *cap_data = (struct captured_data *)ds->pcap_data;
        struct pcap_stat ps;

      if(!cap_data->pcap) {
            cli_print(cli, "    Libpcap not initialized or interface down");
            return;
      }
      pcap_stats((pcap_t *) cap_data->pcap, &ps);

      cli_print(cli, "    Libpcap %s %s: %s: %u packets received, %u dropped",\
            ds->src_cmd, (ds->ds_flags&DS_PROMISC)?"promisc":"",\
            dlt[cap_data->link_type_idx].descr, ps.ps_recv, ps.ps_drop);
}

void ds_libpcap_cancel(void *ptr)
{
      pcap_t      **pcap = (pcap_t**)ptr;
      if(*pcap)
            pcap_close(*pcap);
      pcap=NULL;
}

void pcap_callback(unsigned char *args, const struct pcap_pkthdr *hdr,
    const unsigned char *packet)
{
      Service_DS  *ds   = (Service_DS*)args;
      FlowEngine  *FE   = ds->FE;

      struct captured_data *cap_data = (struct captured_data *)ds->pcap_data;

      u_short                 ether_type;
      struct ip         *ip;
      struct pcap_ipv4_key    pcap_flow_key;
      entry             *flow_entry;

      bzero(&pcap_flow_key, sizeof(struct pcap_ipv4_key));

      switch (cap_data->datalink) {
#ifdef DLT_EN10MB
            case DLT_EN10MB:
                  register const struct ether_header *ep;
                  ep = (struct ether_header *)packet;
                  ether_type = ntohs(ep->ether_type);
                  packet += ETHER_HDR_LEN;
                        break;
#endif
#ifdef DLT_LINUX_SLL
            case DLT_LINUX_SLL:
                  if (hdr->len < SLL_HDR_LEN) return;     /* This should never happened */

                  register const struct sll_header *sllp;
                        sllp = (struct sll_header *)packet;

                  ether_type = ntohs(sllp->sll_protocol);
                        if (ether_type <= ETHERMTU) return; /* We got LLC layer. I don't know if IP is possible at this level */
                        packet += SLL_HDR_LEN;
                        break;
#endif
                default:
                        ether_type = 0xFFFF;
                        break;

      }

      if (ether_type != 0xFFFF) {
recurse:
            if (ether_type == ETHERTYPE_VLAN) {
                  ether_type = ntohs(*(u_int16_t *) (packet + 2));
                  pcap_flow_key.dot1x = *(u_int16_t *)packet;
                  packet += 4;
                  if (ether_type > ETHERMTU)
                        goto recurse;

            }
            if (ether_type != ETHERTYPE_IP) return;

            ip = (struct ip *)packet;
      } else
            ip = (struct ip *)(packet + cap_data->offset);

      IPv4GetKey(ip, (struct ipv4_key*)&pcap_flow_key);

      if(FE->Process((u_char *)&pcap_flow_key, 1, ntohs(ip->ip_len), &flow_entry) == -1) {
            IPv4FillFlow((struct ipv4_key*)&pcap_flow_key, flow_entry);
            if(pcap_flow_key.dot1x) {
                  struct vlan_info_value *vlan_info = (struct vlan_info_value*)flow_entry->flow->put(ATTR_VLAN_INFO);
                  vlan_info->dot1x = pcap_flow_key.dot1x;
            }
#ifdef LAYER7_FILTER
            if (ds->layer7_detect!=LAYER7_DETECT_NONE) layer7_addinfo(pcap_flow_key.tcp_info.dst_port, flow_entry);
#endif
      }

#ifdef LAYER7_FILTER
      if (ds->layer7_detect!=LAYER7_DETECT_NONE) layer7_checkinfo(pcap_flow_key.tcp_info.dst_port, flow_entry, ip);
#endif

      ds->Measure(FE->tv, hdr->len);
}

#endif

Generated by  Doxygen 1.6.0   Back to index