LCOV - code coverage report
Current view: top level - server - process_packet.c (source / functions) Hit Total Coverage
Test: lcov_coverage_final.info Lines: 53 57 93.0 %
Date: 2014-11-16 Functions: 1 1 100.0 %
Branches: 24 40 60.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  *****************************************************************************
       3                 :            :  *
       4                 :            :  * File:    process_packet.c
       5                 :            :  *
       6                 :            :  * Purpose: Packet parser/decoder for fwknopd server.  Takes the raw packet
       7                 :            :  *          data from libpcap and parses/extracts the packet data payload,
       8                 :            :  *          then creates an FKO context with that data.  If the context
       9                 :            :  *          creation is successful, it is queued for processing.
      10                 :            :  *
      11                 :            :  *  Fwknop is developed primarily by the people listed in the file 'AUTHORS'.
      12                 :            :  *  Copyright (C) 2009-2014 fwknop developers and contributors. For a full
      13                 :            :  *  list of contributors, see the file 'CREDITS'.
      14                 :            :  *
      15                 :            :  *  License (GNU General Public License):
      16                 :            :  *
      17                 :            :  *  This program is free software; you can redistribute it and/or
      18                 :            :  *  modify it under the terms of the GNU General Public License
      19                 :            :  *  as published by the Free Software Foundation; either version 2
      20                 :            :  *  of the License, or (at your option) any later version.
      21                 :            :  *
      22                 :            :  *  This program is distributed in the hope that it will be useful,
      23                 :            :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      24                 :            :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      25                 :            :  *  GNU General Public License for more details.
      26                 :            :  *
      27                 :            :  *  You should have received a copy of the GNU General Public License
      28                 :            :  *  along with this program; if not, write to the Free Software
      29                 :            :  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
      30                 :            :  *  USA
      31                 :            :  *
      32                 :            :  *****************************************************************************
      33                 :            : */
      34                 :            : #include <pcap.h>
      35                 :            : 
      36                 :            : #include "fwknopd_common.h"
      37                 :            : #include "netinet_common.h"
      38                 :            : #include "process_packet.h"
      39                 :            : #include "incoming_spa.h"
      40                 :            : #include "utils.h"
      41                 :            : #include "log_msg.h"
      42                 :            : 
      43                 :            : void
      44                 :      14080 : process_packet(unsigned char *args, const struct pcap_pkthdr *packet_header,
      45                 :            :     const unsigned char *packet)
      46                 :            : {
      47                 :            :     struct ether_header *eth_p;
      48                 :            :     struct iphdr        *iph_p;
      49                 :            :     struct tcphdr       *tcph_p;
      50                 :            :     struct udphdr       *udph_p;
      51                 :            :     struct icmphdr      *icmph_p;
      52                 :            : 
      53                 :            :     unsigned char       *pkt_data;
      54                 :            :     unsigned short      pkt_data_len;
      55                 :            :     unsigned char       *pkt_end;
      56                 :            : 
      57                 :            :     unsigned int        ip_hdr_words;
      58                 :            : 
      59                 :            :     unsigned char       proto;
      60                 :            :     unsigned int        src_ip;
      61                 :            :     unsigned int        dst_ip;
      62                 :            : 
      63                 :      14080 :     unsigned short      src_port = 0;
      64                 :      14080 :     unsigned short      dst_port = 0;
      65                 :            : 
      66                 :            :     unsigned short      eth_type;
      67                 :            : 
      68                 :      14080 :     fko_srv_options_t   *opts = (fko_srv_options_t *)args;
      69                 :            : 
      70                 :      14080 :     int                 offset = opts->data_link_offset;
      71                 :            : 
      72                 :      14080 :     unsigned short      pkt_len = packet_header->len;
      73                 :            : 
      74                 :            :     /* This is a hack to determine if we are using the linux cooked
      75                 :            :      * interface.  We base it on the offset being 16 which is the
      76                 :            :      * value it would be if the datalink is DLT_LINUX_SLL.  I don't
      77                 :            :      * know if this is the correct way to do this, but it seems to work.
      78                 :            :     */
      79                 :      14080 :     unsigned char       assume_cooked = (offset == 16 ? 1 : 0);
      80                 :            : 
      81                 :            :     /* Determine packet end.
      82                 :            :     */
      83                 :      14080 :     pkt_end = (unsigned char *) packet + packet_header->caplen;
      84                 :            : 
      85                 :            :     /* The ethernet header.
      86                 :            :     */
      87                 :      14080 :     eth_p = (struct ether_header*) packet;
      88                 :            : 
      89                 :            :     /* Gotta have a complete ethernet header.
      90                 :            :     */
      91         [ +  - ]:      14080 :     if (packet_header->caplen < ETHER_HDR_LEN)
      92                 :            :         return;
      93                 :            : 
      94         [ -  + ]:      14080 :     eth_type = ntohs(*((unsigned short*)&eth_p->ether_type));
      95                 :            : 
      96         [ -  + ]:      14080 :     if(eth_type == 0x8100) /* 802.1q encapsulated */
      97                 :            :     {
      98                 :          0 :         offset += 4;
      99         [ #  # ]:          0 :         eth_type = ntohs(*(((unsigned short*)&eth_p->ether_type)+2));
     100                 :            :     }
     101                 :            : 
     102                 :            :     /* When using libpcap, pkthdr->len for 802.3 frames include CRC_LEN,
     103                 :            :      * but Ethenet_II frames do not.
     104                 :            :     */
     105         [ +  - ]:      14080 :     if (eth_type > 1500 || assume_cooked == 1)
     106                 :            :     {
     107                 :      14080 :         pkt_len += ETHER_CRC_LEN;
     108                 :            : 
     109         [ -  + ]:      14080 :         if(eth_type == 0xAAAA)      /* 802.2 SNAP */
     110                 :          0 :             offset += 5;
     111                 :            :     }
     112                 :            :     else /* 802.3 Frame */
     113                 :          0 :         offset += 3;
     114                 :            : 
     115                 :            :     /* Make sure the packet length is still valid.
     116                 :            :     */
     117         [ +  + ]:      14080 :     if (! ETHER_IS_VALID_LEN(pkt_len) )
     118                 :            :         return;
     119                 :            : 
     120                 :            :     /* Pull the IP header.
     121                 :            :     */
     122                 :      14071 :     iph_p = (struct iphdr*)(packet + offset);
     123                 :            : 
     124                 :            :     /* If IP header is past calculated packet end, bail.
     125                 :            :     */
     126         [ +  - ]:      14071 :     if ((unsigned char*)(iph_p + 1) > pkt_end)
     127                 :            :         return;
     128                 :            : 
     129                 :            :     /* ip_hdr_words is the number of 32 bit words in the IP header. After
     130                 :            :      * masking of the IPV4 version bits, the number *must* be at least
     131                 :            :      * 5, even without options.
     132                 :            :     */
     133                 :      14071 :     ip_hdr_words = iph_p->ihl & IPV4_VER_MASK;
     134                 :            : 
     135         [ +  - ]:      14071 :     if (ip_hdr_words < MIN_IPV4_WORDS)
     136                 :            :         return;
     137                 :            : 
     138                 :            :     /* Support for the cases where libpcap returns the Ethernet Frame Check
     139                 :            :      * Sequence (4 bytes at the end of the Ethernet frame) as part of the
     140                 :            :      * capture. libpcap returning the FCS is fairly rare. Default settings on
     141                 :            :      * the following system included an Ethernet FCS in the libpcap capture:
     142                 :            :      *     BeagleBone Black rev C running 3.8.13-bone50 #1 SMP Tue May 13
     143                 :            :      *     13:24:52 UTC 2014 armv7l GNU/Linux
     144                 :            :      *
     145                 :            :      * Calculate the new pkt_end from the length in the ip header.
     146                 :            :     */
     147 [ -  + ][ +  + ]:      14071 :     if(((unsigned char*)iph_p)+ntohs(iph_p->tot_len) == pkt_end-FCS_HEADER_LEN) {
     148                 :          1 :         log_msg(LOG_DEBUG, "Adjusting packet end to account for FCS header on Ethernet frame");
     149                 :          1 :         pkt_end -= FCS_HEADER_LEN;
     150                 :            :     }
     151                 :            : 
     152                 :            :     /* Now, find the packet data payload (depending on IPPROTO).
     153                 :            :     */
     154                 :      14071 :     src_ip = iph_p->saddr;
     155                 :      14071 :     dst_ip = iph_p->daddr;
     156                 :            : 
     157                 :      14071 :     proto = iph_p->protocol;
     158                 :            : 
     159         [ +  + ]:      14071 :     if (proto == IPPROTO_TCP)
     160                 :            :     {
     161                 :            :         /* Process TCP packet
     162                 :            :         */
     163                 :         18 :         tcph_p = (struct tcphdr*)((unsigned char*)iph_p + (ip_hdr_words << 2));
     164                 :            : 
     165         [ -  + ]:         18 :         src_port = ntohs(tcph_p->source);
     166         [ -  + ]:         18 :         dst_port = ntohs(tcph_p->dest);
     167                 :            : 
     168                 :         18 :         pkt_data = ((unsigned char*)(tcph_p+1))+((tcph_p->doff)<<2)-sizeof(struct tcphdr);
     169                 :            : 
     170                 :         18 :         pkt_data_len = (pkt_end-(unsigned char*)iph_p)-(pkt_data-(unsigned char*)iph_p);
     171                 :            :     }
     172         [ +  + ]:      14053 :     else if (proto == IPPROTO_UDP)
     173                 :            :     {
     174                 :            :         /* Process UDP packet
     175                 :            :         */
     176                 :      14051 :         udph_p = (struct udphdr*)((unsigned char*)iph_p + (ip_hdr_words << 2));
     177                 :            : 
     178         [ -  + ]:      14051 :         src_port = ntohs(udph_p->source);
     179         [ -  + ]:      14051 :         dst_port = ntohs(udph_p->dest);
     180                 :            : 
     181                 :      14051 :         pkt_data = ((unsigned char*)(udph_p + 1));
     182                 :      14051 :         pkt_data_len = (pkt_end-(unsigned char*)iph_p)-(pkt_data-(unsigned char*)iph_p);
     183                 :            :     }
     184         [ +  - ]:          2 :     else if (proto == IPPROTO_ICMP)
     185                 :            :     {
     186                 :            :         /* Process ICMP packet
     187                 :            :         */
     188                 :          2 :         icmph_p = (struct icmphdr*)((unsigned char*)iph_p + (ip_hdr_words << 2));
     189                 :            : 
     190                 :          2 :         pkt_data = ((unsigned char*)(icmph_p + 1));
     191                 :          2 :         pkt_data_len = (pkt_end-(unsigned char*)iph_p)-(pkt_data-(unsigned char*)iph_p);
     192                 :            :     }
     193                 :            : 
     194                 :            :     else
     195                 :            :         return;
     196                 :            : 
     197                 :            :     /*
     198                 :            :      * Now we have data. For now, we are not checking IP or port values. We
     199                 :            :      * are relying on the pcap filter. This may change so we do retain the IP
     200                 :            :      * addresses and ports just in case. We just go ahead and queue the
     201                 :            :      * data.
     202                 :            :     */
     203                 :            : 
     204                 :            :     /* Expect the data to be at least the minimum required size.  This check
     205                 :            :      * will weed out a lot of things like small TCP ACK's if the user has a
     206                 :            :      * permissive pcap filter
     207                 :            :     */
     208         [ +  + ]:      14071 :     if(pkt_data_len < MIN_SPA_DATA_SIZE)
     209                 :            :         return;
     210                 :            : 
     211                 :            :     /* Expect the data to not be too large
     212                 :            :     */
     213         [ +  - ]:      14055 :     if(pkt_data_len > MAX_SPA_PACKET_LEN)
     214                 :            :         return;
     215                 :            : 
     216                 :            :     /* Copy the packet for SPA processing
     217                 :            :     */
     218                 :      14055 :     strlcpy((char *)opts->spa_pkt.packet_data, (char *)pkt_data, pkt_data_len+1);
     219                 :      14055 :     opts->spa_pkt.packet_data_len = pkt_data_len;
     220                 :      14055 :     opts->spa_pkt.packet_proto    = proto;
     221                 :      14055 :     opts->spa_pkt.packet_src_ip   = src_ip;
     222                 :      14055 :     opts->spa_pkt.packet_dst_ip   = dst_ip;
     223                 :      14055 :     opts->spa_pkt.packet_src_port = src_port;
     224                 :      14055 :     opts->spa_pkt.packet_dst_port = dst_port;
     225                 :            : 
     226                 :      14055 :     incoming_spa(opts);
     227                 :            : 
     228                 :      14055 :     return;
     229                 :            : }
     230                 :            : 
     231                 :            : /***EOF***/

Generated by: LCOV version 1.10