]> The Tcpdump Group git mirrors - libpcap/blob - pcap-util.c
Merge pull request #1229 from guyharris/more-pcap-to-pcapint
[libpcap] / pcap-util.c
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-util.c - common code for various 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 u_int 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 pcapint_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 pcapint_fixup_pcap_pkthdr(linktype, hdr, data);
439 }
440
441 void
442 pcapint_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 }