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(&eth->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(&eth->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