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*)ð_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*)ð_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***/
|