LCOV - code coverage report
Current view: top level - fwknop.git/server - process_packet.c (source / functions) Hit Total Coverage
Test: lcov_coverage_final.info Lines: 50 54 92.6 %
Date: 2014-07-28 Functions: 1 1 100.0 %
Branches: 21 36 58.3 %

           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                 :            : 
      42                 :            : void
      43                 :      15985 : process_packet(unsigned char *args, const struct pcap_pkthdr *packet_header,
      44                 :            :     const unsigned char *packet)
      45                 :            : {
      46                 :            :     struct ether_header *eth_p;
      47                 :            :     struct iphdr        *iph_p;
      48                 :            :     struct tcphdr       *tcph_p;
      49                 :            :     struct udphdr       *udph_p;
      50                 :            :     struct icmphdr      *icmph_p;
      51                 :            : 
      52                 :            :     unsigned char       *pkt_data;
      53                 :            :     unsigned short      pkt_data_len;
      54                 :            :     unsigned char       *pkt_end;
      55                 :            : 
      56                 :            :     unsigned int        ip_hdr_words;
      57                 :            : 
      58                 :            :     unsigned char       proto;
      59                 :            :     unsigned int        src_ip;
      60                 :            :     unsigned int        dst_ip;
      61                 :            : 
      62                 :      15985 :     unsigned short      src_port = 0;
      63                 :      15985 :     unsigned short      dst_port = 0;
      64                 :            : 
      65                 :            :     unsigned short      eth_type;
      66                 :            : 
      67                 :      15985 :     fko_srv_options_t   *opts = (fko_srv_options_t *)args;
      68                 :            : 
      69                 :      15985 :     int                 offset = opts->data_link_offset;
      70                 :            : 
      71                 :      15985 :     unsigned short      pkt_len = packet_header->len;
      72                 :            : 
      73                 :            :     /* This is a hack to determine if we are using the linux cooked
      74                 :            :      * interface.  We base it on the offset being 16 which is the
      75                 :            :      * value it would be if the datalink is DLT_LINUX_SLL.  I don't
      76                 :            :      * know if this is the correct way to do this, but it seems to work.
      77                 :            :     */
      78                 :      15985 :     unsigned char       assume_cooked = (offset == 16 ? 1 : 0);
      79                 :            : 
      80                 :            :     /* Determine packet end.
      81                 :            :     */
      82                 :      15985 :     pkt_end = (unsigned char *) packet + packet_header->caplen;
      83                 :            : 
      84                 :            :     /* The ethernet header.
      85                 :            :     */
      86                 :      15985 :     eth_p = (struct ether_header*) packet;
      87                 :            : 
      88                 :            :     /* Gotta have a complete ethernet header.
      89                 :            :     */
      90         [ +  - ]:      15985 :     if (packet_header->caplen < ETHER_HDR_LEN)
      91                 :            :         return;
      92                 :            : 
      93         [ -  + ]:      15985 :     eth_type = ntohs(*((unsigned short*)&eth_p->ether_type));
      94                 :            : 
      95         [ -  + ]:      15985 :     if(eth_type == 0x8100) /* 802.1q encapsulated */
      96                 :            :     {
      97                 :          0 :         offset += 4;
      98         [ #  # ]:          0 :         eth_type = ntohs(*(((unsigned short*)&eth_p->ether_type)+2));
      99                 :            :     }
     100                 :            : 
     101                 :            :     /* When using libpcap, pkthdr->len for 802.3 frames include CRC_LEN,
     102                 :            :      * but Ethenet_II frames do not.
     103                 :            :     */
     104         [ +  - ]:      15985 :     if (eth_type > 1500 || assume_cooked == 1)
     105                 :            :     {
     106                 :      15985 :         pkt_len += ETHER_CRC_LEN;
     107                 :            : 
     108         [ -  + ]:      15985 :         if(eth_type == 0xAAAA)      /* 802.2 SNAP */
     109                 :          0 :             offset += 5;
     110                 :            :     }
     111                 :            :     else /* 802.3 Frame */
     112                 :          0 :         offset += 3;
     113                 :            : 
     114                 :            :     /* Make sure the packet length is still valid.
     115                 :            :     */
     116         [ +  + ]:      15985 :     if (! ETHER_IS_VALID_LEN(pkt_len) )
     117                 :            :         return;
     118                 :            : 
     119                 :            :     /* Pull the IP header.
     120                 :            :     */
     121                 :      15976 :     iph_p = (struct iphdr*)(packet + offset);
     122                 :            : 
     123                 :            :     /* If IP header is past calculated packet end, bail.
     124                 :            :     */
     125         [ +  - ]:      15976 :     if ((unsigned char*)(iph_p + 1) > pkt_end)
     126                 :            :         return;
     127                 :            : 
     128                 :            :     /* ip_hdr_words is the number of 32 bit words in the IP header. After
     129                 :            :      * masking of the IPV4 version bits, the number *must* be at least
     130                 :            :      * 5, even without options.
     131                 :            :     */
     132                 :      15976 :     ip_hdr_words = iph_p->ihl & IPV4_VER_MASK;
     133                 :            : 
     134         [ +  - ]:      15976 :     if (ip_hdr_words < MIN_IPV4_WORDS)
     135                 :            :         return;
     136                 :            : 
     137                 :            :     /* Now, find the packet data payload (depending on IPPROTO).
     138                 :            :     */
     139                 :      15976 :     src_ip = iph_p->saddr;
     140                 :      15976 :     dst_ip = iph_p->daddr;
     141                 :            : 
     142                 :      15976 :     proto = iph_p->protocol;
     143                 :            : 
     144         [ +  + ]:      15976 :     if (proto == IPPROTO_TCP)
     145                 :            :     {
     146                 :            :         /* Process TCP packet
     147                 :            :         */
     148                 :         18 :         tcph_p = (struct tcphdr*)((unsigned char*)iph_p + (ip_hdr_words << 2));
     149                 :            : 
     150         [ -  + ]:         18 :         src_port = ntohs(tcph_p->source);
     151         [ -  + ]:         18 :         dst_port = ntohs(tcph_p->dest);
     152                 :            : 
     153                 :         18 :         pkt_data = ((unsigned char*)(tcph_p+1))+((tcph_p->doff)<<2)-sizeof(struct tcphdr);
     154                 :            : 
     155                 :         18 :         pkt_data_len = (pkt_end-(unsigned char*)iph_p)-(pkt_data-(unsigned char*)iph_p);
     156                 :            :     }
     157         [ +  + ]:      15958 :     else if (proto == IPPROTO_UDP)
     158                 :            :     {
     159                 :            :         /* Process UDP packet
     160                 :            :         */
     161                 :      15956 :         udph_p = (struct udphdr*)((unsigned char*)iph_p + (ip_hdr_words << 2));
     162                 :            : 
     163         [ -  + ]:      15956 :         src_port = ntohs(udph_p->source);
     164         [ -  + ]:      15956 :         dst_port = ntohs(udph_p->dest);
     165                 :            : 
     166                 :      15956 :         pkt_data = ((unsigned char*)(udph_p + 1));
     167                 :      15956 :         pkt_data_len = (pkt_end-(unsigned char*)iph_p)-(pkt_data-(unsigned char*)iph_p);
     168                 :            :     }
     169         [ +  - ]:          2 :     else if (proto == IPPROTO_ICMP)
     170                 :            :     {
     171                 :            :         /* Process ICMP packet
     172                 :            :         */
     173                 :          2 :         icmph_p = (struct icmphdr*)((unsigned char*)iph_p + (ip_hdr_words << 2));
     174                 :            : 
     175                 :          2 :         pkt_data = ((unsigned char*)(icmph_p + 1));
     176                 :          2 :         pkt_data_len = (pkt_end-(unsigned char*)iph_p)-(pkt_data-(unsigned char*)iph_p);
     177                 :            :     }
     178                 :            : 
     179                 :            :     else
     180                 :            :         return;
     181                 :            : 
     182                 :            :     /*
     183                 :            :      * Now we have data. For now, we are not checking IP or port values. We
     184                 :            :      * are relying on the pcap filter. This may change so we do retain the IP
     185                 :            :      * addresses and ports just in case. We just go ahead and queue the
     186                 :            :      * data.
     187                 :            :     */
     188                 :            : 
     189                 :            :     /* Expect the data to be at least the minimum required size.  This check
     190                 :            :      * will weed out a lot of things like small TCP ACK's if the user has a
     191                 :            :      * permissive pcap filter
     192                 :            :     */
     193         [ +  + ]:      15976 :     if(pkt_data_len < MIN_SPA_DATA_SIZE)
     194                 :            :         return;
     195                 :            : 
     196                 :            :     /* Expect the data to not be too large
     197                 :            :     */
     198         [ +  - ]:      15960 :     if(pkt_data_len > MAX_SPA_PACKET_LEN)
     199                 :            :         return;
     200                 :            : 
     201                 :            :     /* Copy the packet for SPA processing
     202                 :            :     */
     203                 :      15960 :     strlcpy((char *)opts->spa_pkt.packet_data, (char *)pkt_data, pkt_data_len+1);
     204                 :      15960 :     opts->spa_pkt.packet_data_len = pkt_data_len;
     205                 :      15960 :     opts->spa_pkt.packet_proto    = proto;
     206                 :      15960 :     opts->spa_pkt.packet_src_ip   = src_ip;
     207                 :      15960 :     opts->spa_pkt.packet_dst_ip   = dst_ip;
     208                 :      15960 :     opts->spa_pkt.packet_src_port = src_port;
     209                 :      15960 :     opts->spa_pkt.packet_dst_port = dst_port;
     210                 :            : 
     211                 :      15960 :     incoming_spa(opts);
     212                 :            : 
     213                 :      15960 :     return;
     214                 :            : }
     215                 :            : 
     216                 :            : /***EOF***/

Generated by: LCOV version 1.9