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