1 /*
2 * Copyright (c) 2009-2012 by Farsight Security, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /* Import. */
18
19 #include <pcap.h>
20
21 #include "private.h"
22
23 /* Macros. */
24
25 #define advance_pkt(pkt, len, sz) do { \
26 (pkt) += (sz); \
27 (len) -= (sz); \
28 } while (0)
29
30 /* Export. */
31
32 nmsg_res
nmsg_ipdg_parse(struct nmsg_ipdg * dg,unsigned etype,size_t len,const u_char * pkt)33 nmsg_ipdg_parse(struct nmsg_ipdg *dg, unsigned etype, size_t len,
34 const u_char *pkt)
35 {
36 return (_nmsg_ipdg_parse_reasm(dg, etype, len, pkt,
37 NULL, NULL, NULL, NULL, 0));
38 }
39
40 nmsg_res
nmsg_ipdg_parse_pcap(struct nmsg_ipdg * dg,struct nmsg_pcap * pcap,struct pcap_pkthdr * pkt_hdr,const u_char * pkt)41 nmsg_ipdg_parse_pcap(struct nmsg_ipdg *dg, struct nmsg_pcap *pcap,
42 struct pcap_pkthdr *pkt_hdr, const u_char *pkt)
43 {
44 int defrag = 0;
45 size_t len = pkt_hdr->caplen;
46 unsigned etype = 0;
47 unsigned new_len = NMSG_IPSZ_MAX;
48 nmsg_res res;
49
50 /* only operate on complete packets */
51 if (pkt_hdr->caplen != pkt_hdr->len)
52 return (nmsg_res_again);
53
54 /* process data link header */
55 switch (pcap->datalink) {
56 case DLT_EN10MB: {
57 const struct nmsg_ethhdr *eth;
58
59 if (len < sizeof(*eth))
60 return (nmsg_res_again);
61
62 eth = (const struct nmsg_ethhdr *) pkt;
63 advance_pkt(pkt, len, sizeof(struct nmsg_ethhdr));
64 load_net16(ð->ether_type, &etype);
65 if (etype == ETHERTYPE_VLAN) {
66 if (len < 4)
67 return (nmsg_res_again);
68 advance_pkt(pkt, len, 2);
69 load_net16(pkt, &etype);
70 advance_pkt(pkt, len, 2);
71 }
72 break;
73 }
74 case DLT_RAW: {
75 const struct nmsg_iphdr *ip;
76
77 if (len < sizeof(*ip))
78 return (nmsg_res_again);
79 ip = (const struct nmsg_iphdr *) pkt;
80
81 if (ip->ip_v == 4) {
82 etype = ETHERTYPE_IP;
83 } else if (ip->ip_v == 6) {
84 etype = ETHERTYPE_IPV6;
85 } else {
86 return (nmsg_res_again);
87 }
88 break;
89 }
90 #ifdef DLT_LINUX_SLL
91 case DLT_LINUX_SLL: {
92 if (len < 16)
93 return (nmsg_res_again);
94 advance_pkt(pkt, len, ETHER_HDR_LEN);
95 load_net16(pkt, &etype);
96 advance_pkt(pkt, len, 2);
97 break;
98 }
99 #endif
100 } /* end switch */
101
102 res = _nmsg_ipdg_parse_reasm(dg, etype, len, pkt, pcap->reasm,
103 &new_len, pcap->new_pkt, &defrag,
104 pkt_hdr->ts.tv_sec);
105 if (res == nmsg_res_success && defrag == 1) {
106 /* refilter the newly reassembled datagram */
107 struct bpf_insn *fcode = pcap->userbpf.bf_insns;
108
109 if (fcode != NULL &&
110 bpf_filter(fcode, (u_char *) dg->network, dg->len_network,
111 dg->len_network) == 0)
112 {
113 return (nmsg_res_again);
114 }
115 }
116 return (res);
117 }
118
119 nmsg_res
_nmsg_ipdg_parse_reasm(struct nmsg_ipdg * dg,unsigned etype,size_t len,const u_char * pkt,struct _nmsg_ipreasm * reasm,unsigned * new_len,u_char * new_pkt,int * defrag,uint64_t timestamp)120 _nmsg_ipdg_parse_reasm(struct nmsg_ipdg *dg, unsigned etype, size_t len,
121 const u_char *pkt, struct _nmsg_ipreasm *reasm,
122 unsigned *new_len, u_char *new_pkt, int *defrag,
123 uint64_t timestamp)
124 {
125 bool is_fragment = false;
126 unsigned frag_hdr_offset = 0;
127 unsigned tp_payload_len = 0;
128
129 dg->network = pkt;
130 dg->len_network = len;
131
132 /* process network header */
133 switch (etype) {
134 case ETHERTYPE_IP: {
135 const struct nmsg_iphdr *ip;
136 unsigned ip_off;
137
138 ip = (const struct nmsg_iphdr *) dg->network;
139 advance_pkt(pkt, len, ip->ip_hl << 2);
140
141 load_net16(&ip->ip_off, &ip_off);
142 if ((ip_off & IP_OFFMASK) != 0 ||
143 (ip_off & IP_MF) != 0)
144 {
145 is_fragment = true;
146 }
147 dg->proto_network = PF_INET;
148 dg->proto_transport = ip->ip_p;
149 break;
150 }
151 case ETHERTYPE_IPV6: {
152 const struct ip6_hdr *ip6;
153 uint16_t payload_len;
154 uint8_t nexthdr;
155 unsigned thusfar;
156
157 if (len < sizeof(*ip6))
158 return (nmsg_res_again);
159 ip6 = (const struct ip6_hdr *) dg->network;
160 if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION)
161 return (nmsg_res_again);
162
163 nexthdr = ip6->ip6_nxt;
164 thusfar = sizeof(struct ip6_hdr);
165 load_net16(&ip6->ip6_plen, &payload_len);
166
167 while (nexthdr == IPPROTO_ROUTING ||
168 nexthdr == IPPROTO_HOPOPTS ||
169 nexthdr == IPPROTO_FRAGMENT ||
170 nexthdr == IPPROTO_DSTOPTS ||
171 nexthdr == IPPROTO_AH ||
172 nexthdr == IPPROTO_ESP)
173 {
174 struct {
175 uint8_t nexthdr;
176 uint8_t length;
177 } ext_hdr;
178 uint16_t ext_hdr_len;
179
180 /* catch broken packets */
181 if ((thusfar + sizeof(ext_hdr)) > len)
182 return (nmsg_res_again);
183
184 if (nexthdr == IPPROTO_FRAGMENT) {
185 frag_hdr_offset = thusfar;
186 is_fragment = true;
187 break;
188 }
189
190 memcpy(&ext_hdr, (const u_char *) ip6 + thusfar,
191 sizeof(ext_hdr));
192 nexthdr = ext_hdr.nexthdr;
193 ext_hdr_len = (8 * (ntohs(ext_hdr.length) + 1));
194
195 if (ext_hdr_len > payload_len)
196 return (nmsg_res_again);
197
198 thusfar += ext_hdr_len;
199 payload_len -= ext_hdr_len;
200 }
201
202 if ((thusfar + payload_len) > len || payload_len == 0)
203 return (nmsg_res_again);
204
205 advance_pkt(pkt, len, thusfar);
206
207 dg->proto_network = PF_INET6;
208 dg->proto_transport = nexthdr;
209 break;
210 }
211 default:
212 return (nmsg_res_again);
213 break;
214 } /* end switch */
215
216 /* handle IPv4 and IPv6 fragments */
217 if (is_fragment == true && reasm != NULL) {
218 bool rres;
219
220 rres = reasm_ip_next(reasm, dg->network, dg->len_network,
221 frag_hdr_offset, timestamp,
222 new_pkt, new_len);
223 if (rres == false || *new_len == 0) {
224 /* not all fragments have been received */
225 return (nmsg_res_again);
226 }
227 /* the datagram has been fully reassembled */
228 if (defrag != NULL)
229 *defrag = 1;
230 return (nmsg_ipdg_parse(dg, etype, *new_len, new_pkt));
231 }
232 if (is_fragment == true && reasm == NULL)
233 return (nmsg_res_again);
234
235 dg->transport = pkt;
236 dg->len_transport = len;
237
238 /* process transport header */
239 switch (dg->proto_transport) {
240 case IPPROTO_UDP: {
241 struct nmsg_udphdr *udp;
242
243 if (len < sizeof(struct nmsg_udphdr))
244 return (nmsg_res_again);
245 udp = (struct nmsg_udphdr *) pkt;
246 load_net16(&udp->uh_ulen, &tp_payload_len);
247 if (tp_payload_len >= 8)
248 tp_payload_len -= 8;
249 advance_pkt(pkt, len, sizeof(struct nmsg_udphdr));
250
251 dg->payload = pkt;
252 dg->len_payload = tp_payload_len;
253 if (dg->len_payload > len)
254 dg->len_payload = len;
255 break;
256 }
257 default:
258 return (nmsg_res_again);
259 break;
260 } /* end switch */
261
262 return (nmsg_res_success);
263 }
264
265 nmsg_res
nmsg_ipdg_parse_pcap_raw(struct nmsg_ipdg * dg,int datalink,const uint8_t * pkt,size_t len)266 nmsg_ipdg_parse_pcap_raw(struct nmsg_ipdg *dg, int datalink, const uint8_t *pkt, size_t len)
267 {
268 bool is_initial_fragment = false;
269 bool is_fragment = false;
270 unsigned etype = 0;
271 unsigned tp_payload_len = 0;
272
273 /* process data link header */
274 switch (datalink) {
275 case DLT_EN10MB: {
276 const struct nmsg_ethhdr *eth;
277
278 if (len < sizeof(*eth))
279 return (nmsg_res_again);
280
281 eth = (const struct nmsg_ethhdr *) pkt;
282 advance_pkt(pkt, len, sizeof(struct nmsg_ethhdr));
283 load_net16(ð->ether_type, &etype);
284 if (etype == ETHERTYPE_VLAN) {
285 if (len < 4)
286 return (nmsg_res_again);
287 advance_pkt(pkt, len, 2);
288 load_net16(pkt, &etype);
289 advance_pkt(pkt, len, 2);
290 }
291 break;
292 }
293 case DLT_RAW: {
294 const struct nmsg_iphdr *ip;
295
296 if (len < sizeof(*ip))
297 return (nmsg_res_again);
298 ip = (const struct nmsg_iphdr *) pkt;
299
300 if (ip->ip_v == 4) {
301 etype = ETHERTYPE_IP;
302 } else if (ip->ip_v == 6) {
303 etype = ETHERTYPE_IPV6;
304 } else {
305 return (nmsg_res_again);
306 }
307 break;
308 }
309 #ifdef DLT_LINUX_SLL
310 case DLT_LINUX_SLL: {
311 if (len < 16)
312 return (nmsg_res_again);
313 advance_pkt(pkt, len, ETHER_HDR_LEN);
314 load_net16(pkt, &etype);
315 advance_pkt(pkt, len, 2);
316 break;
317 }
318 #endif
319 } /* end switch */
320
321 dg->network = pkt;
322 dg->len_network = len;
323
324 /* process network header */
325 switch (etype) {
326 case ETHERTYPE_IP: {
327 const struct nmsg_iphdr *ip;
328 unsigned ip_off;
329
330 ip = (const struct nmsg_iphdr *) dg->network;
331 advance_pkt(pkt, len, ip->ip_hl << 2);
332
333 load_net16(&ip->ip_off, &ip_off);
334 if ((ip_off & IP_OFFMASK) != 0 ||
335 (ip_off & IP_MF) != 0)
336 {
337 is_fragment = true;
338 }
339 if ((ip_off & IP_OFFMASK) == 0)
340 is_initial_fragment = true;
341 dg->proto_network = PF_INET;
342 dg->proto_transport = ip->ip_p;
343 break;
344 }
345 case ETHERTYPE_IPV6: {
346 const struct ip6_hdr *ip6;
347 const struct ip6_frag *frag;
348 uint16_t payload_len;
349 uint8_t nexthdr;
350 unsigned thusfar;
351
352 if (len < sizeof(*ip6))
353 return (nmsg_res_again);
354 ip6 = (const struct ip6_hdr *) dg->network;
355 if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION)
356 return (nmsg_res_again);
357
358 nexthdr = ip6->ip6_nxt;
359 thusfar = sizeof(struct ip6_hdr);
360 load_net16(&ip6->ip6_plen, &payload_len);
361
362 while (nexthdr == IPPROTO_ROUTING ||
363 nexthdr == IPPROTO_HOPOPTS ||
364 nexthdr == IPPROTO_FRAGMENT ||
365 nexthdr == IPPROTO_DSTOPTS ||
366 nexthdr == IPPROTO_AH ||
367 nexthdr == IPPROTO_ESP)
368 {
369 struct {
370 uint8_t nexthdr;
371 uint8_t length;
372 } ext_hdr;
373 uint16_t ext_hdr_len;
374
375 /* catch broken packets */
376 if ((thusfar + sizeof(ext_hdr)) > len)
377 return (nmsg_res_again);
378
379 if (nexthdr == IPPROTO_FRAGMENT) {
380 is_fragment = true;
381 frag = (const struct ip6_frag *) (dg->network + thusfar);
382 if ((frag->ip6f_offlg & IP6F_OFF_MASK) == 0)
383 is_initial_fragment = true;
384 }
385
386 memcpy(&ext_hdr, (const u_char *) ip6 + thusfar,
387 sizeof(ext_hdr));
388 nexthdr = ext_hdr.nexthdr;
389 ext_hdr_len = (8 * (ntohs(ext_hdr.length) + 1));
390
391 if (ext_hdr_len > payload_len)
392 return (nmsg_res_again);
393
394 thusfar += ext_hdr_len;
395 payload_len -= ext_hdr_len;
396
397 if (is_fragment)
398 break;
399 }
400
401 if ((thusfar + payload_len) > len || payload_len == 0)
402 return (nmsg_res_again);
403
404 advance_pkt(pkt, len, thusfar);
405
406 dg->proto_network = PF_INET6;
407 dg->proto_transport = nexthdr;
408 break;
409 }
410 default:
411 return (nmsg_res_again);
412 break;
413 } /* end switch */
414
415 if (is_fragment) {
416 if (is_initial_fragment) {
417 dg->transport = pkt;
418 dg->len_transport = len;
419 } else {
420 dg->transport = NULL;
421 dg->len_transport = 0;
422 dg->payload = pkt;
423 dg->len_payload = len;
424 return (nmsg_res_success);
425 }
426 } else {
427 dg->transport = pkt;
428 dg->len_transport = len;
429 }
430
431 /* process transport header */
432 switch (dg->proto_transport) {
433 case IPPROTO_UDP: {
434 struct nmsg_udphdr *udp;
435
436 if (len < sizeof(struct nmsg_udphdr))
437 return (nmsg_res_again);
438 udp = (struct nmsg_udphdr *) pkt;
439 load_net16(&udp->uh_ulen, &tp_payload_len);
440 if (tp_payload_len >= 8)
441 tp_payload_len -= 8;
442 advance_pkt(pkt, len, sizeof(struct nmsg_udphdr));
443
444 dg->payload = pkt;
445 dg->len_payload = tp_payload_len;
446 if (dg->len_payload > len)
447 dg->len_payload = len;
448 break;
449 }
450 case IPPROTO_TCP: {
451 struct nmsg_tcphdr *tcp;
452
453 if (len < sizeof(struct nmsg_tcphdr))
454 return (nmsg_res_again);
455 tcp = (struct nmsg_tcphdr *) pkt;
456 tp_payload_len = dg->len_network - 4 * tcp->th_off;
457 advance_pkt(pkt, len, 4 * tcp->th_off);
458 dg->payload = pkt;
459 dg->len_payload = tp_payload_len;
460 if (dg->len_payload > len)
461 dg->len_payload = len;
462 break;
463 }
464 case IPPROTO_ICMP: {
465 if (len < sizeof(struct nmsg_icmphdr))
466 return (nmsg_res_again);
467 advance_pkt(pkt, len, sizeof(struct nmsg_icmphdr));
468 dg->payload = pkt;
469 dg->len_payload = len;
470 break;
471 }
472 default:
473 return (nmsg_res_again);
474 break;
475 } /* end switch */
476
477 return (nmsg_res_success);
478 }
479