xref: /freebsd/contrib/libpcap/pcap-util.c (revision f81cdf24ba5436367377f7c8e8f51f6df2a75ca7)
1 /*
2  * Copyright (c) 1993, 1994, 1995, 1996, 1997
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that: (1) source code distributions
7  * retain the above copyright notice and this paragraph in its entirety, (2)
8  * distributions including binary code include the above copyright notice and
9  * this paragraph in its entirety in the documentation or other materials
10  * provided with the distribution, and (3) all advertising materials mentioning
11  * features or use of this software display the following acknowledgement:
12  * ``This product includes software developed by the University of California,
13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14  * the University nor the names of its contributors may be used to endorse
15  * or promote products derived from this software without specific prior
16  * written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  *
21  * pcap-common.c - common code for pcap and pcapng files
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <pcap-types.h>
29 
30 #include "pcap-int.h"
31 #include "extract.h"
32 #include "pcap-usb-linux-common.h"
33 
34 #include "pcap-util.h"
35 
36 #include "pflog.h"
37 #include "pcap/can_socketcan.h"
38 #include "pcap/sll.h"
39 #include "pcap/usb.h"
40 #include "pcap/nflog.h"
41 
42 /*
43  * Most versions of the DLT_PFLOG pseudo-header have UID and PID fields
44  * that are saved in host byte order.
45  *
46  * When reading a DLT_PFLOG packet, we need to convert those fields from
47  * the byte order of the host that wrote the file to this host's byte
48  * order.
49  */
50 static void
51 swap_pflog_header(const struct pcap_pkthdr *hdr, u_char *buf)
52 {
53 	u_int caplen = hdr->caplen;
54 	u_int length = hdr->len;
55 	u_int pfloghdr_length;
56 	struct pfloghdr *pflhdr = (struct pfloghdr *)buf;
57 
58 	if (caplen < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid) ||
59 	    length < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid)) {
60 		/* Not enough data to have the uid field */
61 		return;
62 	}
63 
64 	pfloghdr_length = pflhdr->length;
65 
66 	if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, uid) + sizeof pflhdr->uid)) {
67 		/* Header doesn't include uid field */
68 		return;
69 	}
70 	pflhdr->uid = SWAPLONG(pflhdr->uid);
71 
72 	if (caplen < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid) ||
73 	    length < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid)) {
74 		/* Not enough data to have the pid field */
75 		return;
76 	}
77 	if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, pid) + sizeof pflhdr->pid)) {
78 		/* Header doesn't include pid field */
79 		return;
80 	}
81 	pflhdr->pid = SWAPLONG(pflhdr->pid);
82 
83 	if (caplen < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid) ||
84 	    length < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid)) {
85 		/* Not enough data to have the rule_uid field */
86 		return;
87 	}
88 	if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, rule_uid) + sizeof pflhdr->rule_uid)) {
89 		/* Header doesn't include rule_uid field */
90 		return;
91 	}
92 	pflhdr->rule_uid = SWAPLONG(pflhdr->rule_uid);
93 
94 	if (caplen < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid) ||
95 	    length < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid)) {
96 		/* Not enough data to have the rule_pid field */
97 		return;
98 	}
99 	if (pfloghdr_length < (u_int) (offsetof(struct pfloghdr, rule_pid) + sizeof pflhdr->rule_pid)) {
100 		/* Header doesn't include rule_pid field */
101 		return;
102 	}
103 	pflhdr->rule_pid = SWAPLONG(pflhdr->rule_pid);
104 }
105 
106 /*
107  * DLT_LINUX_SLL packets with a protocol type of LINUX_SLL_P_CAN or
108  * LINUX_SLL_P_CANFD have SocketCAN headers in front of the payload,
109  * with the CAN ID being in host byte order.
110  *
111  * When reading a DLT_LINUX_SLL packet, we need to check for those
112  * packets and convert the CAN ID from the byte order of the host that
113  * wrote the file to this host's byte order.
114  */
115 static void
116 swap_linux_sll_header(const struct pcap_pkthdr *hdr, u_char *buf)
117 {
118 	u_int caplen = hdr->caplen;
119 	u_int length = hdr->len;
120 	struct sll_header *shdr = (struct sll_header *)buf;
121 	uint16_t protocol;
122 	pcap_can_socketcan_hdr *chdr;
123 
124 	if (caplen < (u_int) sizeof(struct sll_header) ||
125 	    length < (u_int) sizeof(struct sll_header)) {
126 		/* Not enough data to have the protocol field */
127 		return;
128 	}
129 
130 	protocol = EXTRACT_BE_U_2(&shdr->sll_protocol);
131 	if (protocol != LINUX_SLL_P_CAN && protocol != LINUX_SLL_P_CANFD)
132 		return;
133 
134 	/*
135 	 * SocketCAN packet; fix up the packet's header.
136 	 */
137 	chdr = (pcap_can_socketcan_hdr *)(buf + sizeof(struct sll_header));
138 	if (caplen < (u_int) sizeof(struct sll_header) + sizeof(chdr->can_id) ||
139 	    length < (u_int) sizeof(struct sll_header) + sizeof(chdr->can_id)) {
140 		/* Not enough data to have the CAN ID */
141 		return;
142 	}
143 	chdr->can_id = SWAPLONG(chdr->can_id);
144 }
145 
146 /*
147  * The same applies for DLT_LINUX_SLL2.
148  */
149 static void
150 swap_linux_sll2_header(const struct pcap_pkthdr *hdr, u_char *buf)
151 {
152 	u_int caplen = hdr->caplen;
153 	u_int length = hdr->len;
154 	struct sll2_header *shdr = (struct sll2_header *)buf;
155 	uint16_t protocol;
156 	pcap_can_socketcan_hdr *chdr;
157 
158 	if (caplen < (u_int) sizeof(struct sll2_header) ||
159 	    length < (u_int) sizeof(struct sll2_header)) {
160 		/* Not enough data to have the protocol field */
161 		return;
162 	}
163 
164 	protocol = EXTRACT_BE_U_2(&shdr->sll2_protocol);
165 	if (protocol != LINUX_SLL_P_CAN && protocol != LINUX_SLL_P_CANFD)
166 		return;
167 
168 	/*
169 	 * SocketCAN packet; fix up the packet's header.
170 	 */
171 	chdr = (pcap_can_socketcan_hdr *)(buf + sizeof(struct sll2_header));
172 	if (caplen < (u_int) sizeof(struct sll2_header) + sizeof(chdr->can_id) ||
173 	    length < (u_int) sizeof(struct sll2_header) + sizeof(chdr->can_id)) {
174 		/* Not enough data to have the CAN ID */
175 		return;
176 	}
177 	chdr->can_id = SWAPLONG(chdr->can_id);
178 }
179 
180 /*
181  * The DLT_USB_LINUX and DLT_USB_LINUX_MMAPPED headers are in host
182  * byte order when capturing (it's supplied directly from a
183  * memory-mapped buffer shared by the kernel).
184  *
185  * When reading a DLT_USB_LINUX or DLT_USB_LINUX_MMAPPED packet, we
186  * need to convert it from the byte order of the host that wrote the
187  * file to this host's byte order.
188  */
189 static void
190 swap_linux_usb_header(const struct pcap_pkthdr *hdr, u_char *buf,
191     int header_len_64_bytes)
192 {
193 	pcap_usb_header_mmapped *uhdr = (pcap_usb_header_mmapped *)buf;
194 	bpf_u_int32 offset = 0;
195 
196 	/*
197 	 * "offset" is the offset *past* the field we're swapping;
198 	 * we skip the field *before* checking to make sure
199 	 * the captured data length includes the entire field.
200 	 */
201 
202 	/*
203 	 * The URB id is a totally opaque value; do we really need to
204 	 * convert it to the reading host's byte order???
205 	 */
206 	offset += 8;			/* skip past id */
207 	if (hdr->caplen < offset)
208 		return;
209 	uhdr->id = SWAPLL(uhdr->id);
210 
211 	offset += 4;			/* skip past various 1-byte fields */
212 
213 	offset += 2;			/* skip past bus_id */
214 	if (hdr->caplen < offset)
215 		return;
216 	uhdr->bus_id = SWAPSHORT(uhdr->bus_id);
217 
218 	offset += 2;			/* skip past various 1-byte fields */
219 
220 	offset += 8;			/* skip past ts_sec */
221 	if (hdr->caplen < offset)
222 		return;
223 	uhdr->ts_sec = SWAPLL(uhdr->ts_sec);
224 
225 	offset += 4;			/* skip past ts_usec */
226 	if (hdr->caplen < offset)
227 		return;
228 	uhdr->ts_usec = SWAPLONG(uhdr->ts_usec);
229 
230 	offset += 4;			/* skip past status */
231 	if (hdr->caplen < offset)
232 		return;
233 	uhdr->status = SWAPLONG(uhdr->status);
234 
235 	offset += 4;			/* skip past urb_len */
236 	if (hdr->caplen < offset)
237 		return;
238 	uhdr->urb_len = SWAPLONG(uhdr->urb_len);
239 
240 	offset += 4;			/* skip past data_len */
241 	if (hdr->caplen < offset)
242 		return;
243 	uhdr->data_len = SWAPLONG(uhdr->data_len);
244 
245 	if (uhdr->transfer_type == URB_ISOCHRONOUS) {
246 		offset += 4;			/* skip past s.iso.error_count */
247 		if (hdr->caplen < offset)
248 			return;
249 		uhdr->s.iso.error_count = SWAPLONG(uhdr->s.iso.error_count);
250 
251 		offset += 4;			/* skip past s.iso.numdesc */
252 		if (hdr->caplen < offset)
253 			return;
254 		uhdr->s.iso.numdesc = SWAPLONG(uhdr->s.iso.numdesc);
255 	} else
256 		offset += 8;			/* skip USB setup header */
257 
258 	/*
259 	 * With the old header, there are no isochronous descriptors
260 	 * after the header.
261 	 *
262 	 * With the new header, the actual number of descriptors in
263 	 * the header is not s.iso.numdesc, it's ndesc - only the
264 	 * first N descriptors, for some value of N, are put into
265 	 * the header, and ndesc is set to the actual number copied.
266 	 * In addition, if s.iso.numdesc is negative, no descriptors
267 	 * are captured, and ndesc is set to 0.
268 	 */
269 	if (header_len_64_bytes) {
270 		/*
271 		 * This is either the "version 1" header, with
272 		 * 16 bytes of additional fields at the end, or
273 		 * a "version 0" header from a memory-mapped
274 		 * capture, with 16 bytes of zeroed-out padding
275 		 * at the end.  Byte swap them as if this were
276 		 * a "version 1" header.
277 		 */
278 		offset += 4;			/* skip past interval */
279 		if (hdr->caplen < offset)
280 			return;
281 		uhdr->interval = SWAPLONG(uhdr->interval);
282 
283 		offset += 4;			/* skip past start_frame */
284 		if (hdr->caplen < offset)
285 			return;
286 		uhdr->start_frame = SWAPLONG(uhdr->start_frame);
287 
288 		offset += 4;			/* skip past xfer_flags */
289 		if (hdr->caplen < offset)
290 			return;
291 		uhdr->xfer_flags = SWAPLONG(uhdr->xfer_flags);
292 
293 		offset += 4;			/* skip past ndesc */
294 		if (hdr->caplen < offset)
295 			return;
296 		uhdr->ndesc = SWAPLONG(uhdr->ndesc);
297 
298 		if (uhdr->transfer_type == URB_ISOCHRONOUS) {
299 			/* swap the values in struct linux_usb_isodesc */
300 			usb_isodesc *pisodesc;
301 			uint32_t i;
302 
303 			pisodesc = (usb_isodesc *)(void *)(buf+offset);
304 			for (i = 0; i < uhdr->ndesc; i++) {
305 				offset += 4;		/* skip past status */
306 				if (hdr->caplen < offset)
307 					return;
308 				pisodesc->status = SWAPLONG(pisodesc->status);
309 
310 				offset += 4;		/* skip past offset */
311 				if (hdr->caplen < offset)
312 					return;
313 				pisodesc->offset = SWAPLONG(pisodesc->offset);
314 
315 				offset += 4;		/* skip past len */
316 				if (hdr->caplen < offset)
317 					return;
318 				pisodesc->len = SWAPLONG(pisodesc->len);
319 
320 				offset += 4;		/* skip past padding */
321 
322 				pisodesc++;
323 			}
324 		}
325 	}
326 }
327 
328 /*
329  * The DLT_NFLOG "packets" have a mixture of big-endian and host-byte-order
330  * data.  They begin with a fixed-length header with big-endian fields,
331  * followed by a set of TLVs, where the type and length are in host
332  * byte order but the values are either big-endian or are a raw byte
333  * sequence that's the same regardless of the host's byte order.
334  *
335  * When reading a DLT_NFLOG packet, we need to convert the type and
336  * length values from the byte order of the host that wrote the file
337  * to the byte order of this host.
338  */
339 static void
340 swap_nflog_header(const struct pcap_pkthdr *hdr, u_char *buf)
341 {
342 	u_char *p = buf;
343 	nflog_hdr_t *nfhdr = (nflog_hdr_t *)buf;
344 	nflog_tlv_t *tlv;
345 	u_int caplen = hdr->caplen;
346 	u_int length = hdr->len;
347 	uint16_t size;
348 
349 	if (caplen < (u_int) sizeof(nflog_hdr_t) ||
350 	    length < (u_int) sizeof(nflog_hdr_t)) {
351 		/* Not enough data to have any TLVs. */
352 		return;
353 	}
354 
355 	if (nfhdr->nflog_version != 0) {
356 		/* Unknown NFLOG version */
357 		return;
358 	}
359 
360 	length -= sizeof(nflog_hdr_t);
361 	caplen -= sizeof(nflog_hdr_t);
362 	p += sizeof(nflog_hdr_t);
363 
364 	while (caplen >= sizeof(nflog_tlv_t)) {
365 		tlv = (nflog_tlv_t *) p;
366 
367 		/* Swap the type and length. */
368 		tlv->tlv_type = SWAPSHORT(tlv->tlv_type);
369 		tlv->tlv_length = SWAPSHORT(tlv->tlv_length);
370 
371 		/* Get the length of the TLV. */
372 		size = tlv->tlv_length;
373 		if (size % 4 != 0)
374 			size += 4 - size % 4;
375 
376 		/* Is the TLV's length less than the minimum? */
377 		if (size < sizeof(nflog_tlv_t)) {
378 			/* Yes. Give up now. */
379 			return;
380 		}
381 
382 		/* Do we have enough data for the full TLV? */
383 		if (caplen < size || length < size) {
384 			/* No. */
385 			return;
386 		}
387 
388 		/* Skip over the TLV. */
389 		length -= size;
390 		caplen -= size;
391 		p += size;
392 	}
393 }
394 
395 static void
396 swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr, u_char *data)
397 {
398 	/*
399 	 * Convert pseudo-headers from the byte order of
400 	 * the host on which the file was saved to our
401 	 * byte order, as necessary.
402 	 */
403 	switch (linktype) {
404 
405 	case DLT_PFLOG:
406 		swap_pflog_header(hdr, data);
407 		break;
408 
409 	case DLT_LINUX_SLL:
410 		swap_linux_sll_header(hdr, data);
411 		break;
412 
413 	case DLT_LINUX_SLL2:
414 		swap_linux_sll2_header(hdr, data);
415 		break;
416 
417 	case DLT_USB_LINUX:
418 		swap_linux_usb_header(hdr, data, 0);
419 		break;
420 
421 	case DLT_USB_LINUX_MMAPPED:
422 		swap_linux_usb_header(hdr, data, 1);
423 		break;
424 
425 	case DLT_NFLOG:
426 		swap_nflog_header(hdr, data);
427 		break;
428 	}
429 }
430 
431 void
432 pcap_post_process(int linktype, int swapped, struct pcap_pkthdr *hdr,
433     u_char *data)
434 {
435 	if (swapped)
436 		swap_pseudo_headers(linktype, hdr, data);
437 
438 	fixup_pcap_pkthdr(linktype, hdr, data);
439 }
440 
441 void
442 fixup_pcap_pkthdr(int linktype, struct pcap_pkthdr *hdr, const u_char *data)
443 {
444 	const pcap_usb_header_mmapped *usb_hdr;
445 
446 	usb_hdr = (const pcap_usb_header_mmapped *) data;
447 	if (linktype == DLT_USB_LINUX_MMAPPED &&
448 	    hdr->caplen >= sizeof (pcap_usb_header_mmapped)) {
449 		/*
450 		 * In older versions of libpcap, in memory-mapped captures,
451 		 * the "on-the-bus length" for completion events for
452 		 * incoming isochronous transfers was miscalculated; it
453 		 * needed to be calculated based on the* offsets and lengths
454 		 * in the descriptors, not on the raw URB length, but it
455 		 * wasn't.
456 		 *
457 		 * If this packet contains transferred data (yes, data_flag
458 		 * is 0 if we *do* have data), and the total on-the-network
459 		 * length is equal to the value calculated from the raw URB
460 		 * length, then it might be one of those transfers.
461 		 *
462 		 * We only do this if we have the full USB pseudo-header.
463 		 */
464 		if (!usb_hdr->data_flag &&
465 		    hdr->len == sizeof(pcap_usb_header_mmapped) +
466 		      (usb_hdr->ndesc * sizeof (usb_isodesc)) + usb_hdr->urb_len) {
467 			/*
468 			 * It might need fixing; fix it if it's a completion
469 			 * event for an incoming isochronous transfer.
470 			 */
471 			fix_linux_usb_mmapped_length(hdr, data);
472 		}
473 	}
474 }
475