build: currently do not copy docs to shared docs
[netsniff-ng.git] / pcap_io.h
blobe593922cb550873cf1eabd0890057c2db8e772cf
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * Copyright 2009 - 2013 Daniel Borkmann.
4 * Copyright 2010 Emmanuel Roullit.
5 * Subject to the GPL, version 2.
6 */
8 #ifndef PCAP_IO_H
9 #define PCAP_IO_H
11 #include <unistd.h>
12 #include <stdint.h>
13 #include <stdbool.h>
14 #include <errno.h>
15 #include <sys/time.h>
16 #include <linux/if_packet.h>
18 #include "built_in.h"
19 #include "die.h"
20 #include "xio.h"
22 #define TCPDUMP_MAGIC 0xa1b2c3d4
23 #define ORIGINAL_TCPDUMP_MAGIC TCPDUMP_MAGIC
24 #define NSEC_TCPDUMP_MAGIC 0xa1b23c4d
25 #define KUZNETZOV_TCPDUMP_MAGIC 0xa1b2cd34
26 #define BORKMANN_TCPDUMP_MAGIC 0xa1e2cb12
28 #define PCAP_VERSION_MAJOR 2
29 #define PCAP_VERSION_MINOR 4
30 #define PCAP_DEFAULT_SNAPSHOT_LEN 65535
32 #define LINKTYPE_EN10MB 1 /* Ethernet (10Mb) */
33 #define LINKTYPE_IEEE802_11 105 /* IEEE 802.11 wireless */
35 struct pcap_filehdr {
36 uint32_t magic;
37 uint16_t version_major;
38 uint16_t version_minor;
39 int32_t thiszone;
40 uint32_t sigfigs;
41 uint32_t snaplen;
42 uint32_t linktype;
45 struct pcap_timeval {
46 int32_t tv_sec;
47 int32_t tv_usec;
50 struct pcap_timeval_ns {
51 int32_t tv_sec;
52 int32_t tv_nsec;
55 struct pcap_pkthdr {
56 struct pcap_timeval ts;
57 uint32_t caplen;
58 uint32_t len;
61 struct pcap_pkthdr_ns {
62 struct pcap_timeval_ns ts;
63 uint32_t caplen;
64 uint32_t len;
67 struct pcap_pkthdr_kuz {
68 struct pcap_timeval ts;
69 uint32_t caplen;
70 uint32_t len;
71 int ifindex;
72 uint16_t protocol;
73 uint8_t pkttype;
76 struct pcap_pkthdr_bkm {
77 struct pcap_timeval_ns ts;
78 uint32_t caplen;
79 uint32_t len;
80 uint32_t ifindex;
81 uint16_t protocol;
82 uint8_t hatype;
83 uint8_t pkttype;
86 typedef union {
87 struct pcap_pkthdr ppo;
88 struct pcap_pkthdr_ns ppn;
89 struct pcap_pkthdr_kuz ppk;
90 struct pcap_pkthdr_bkm ppb;
91 uint8_t raw;
92 } pcap_pkthdr_t;
94 enum pcap_type {
95 DEFAULT = ORIGINAL_TCPDUMP_MAGIC,
96 NSEC = NSEC_TCPDUMP_MAGIC,
97 KUZNETZOV = KUZNETZOV_TCPDUMP_MAGIC,
98 BORKMANN = BORKMANN_TCPDUMP_MAGIC,
100 DEFAULT_SWAPPED = ___constant_swab32(ORIGINAL_TCPDUMP_MAGIC),
101 NSEC_SWAPPED = ___constant_swab32(NSEC_TCPDUMP_MAGIC),
102 KUZNETZOV_SWAPPED = ___constant_swab32(KUZNETZOV_TCPDUMP_MAGIC),
103 BORKMANN_SWAPPED = ___constant_swab32(BORKMANN_TCPDUMP_MAGIC),
106 enum pcap_ops_groups {
107 PCAP_OPS_RW = 0,
108 PCAP_OPS_SG,
109 PCAP_OPS_MM,
112 enum pcap_mode {
113 PCAP_MODE_RD = 0,
114 PCAP_MODE_WR,
117 struct pcap_file_ops {
118 void (*init_once_pcap)(void);
119 int (*pull_fhdr_pcap)(int fd, uint32_t *magic, uint32_t *linktype);
120 int (*push_fhdr_pcap)(int fd, uint32_t magic, uint32_t linktype);
121 int (*prepare_access_pcap)(int fd, enum pcap_mode mode, bool jumbo);
122 ssize_t (*write_pcap)(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
123 const uint8_t *packet, size_t len);
124 ssize_t (*read_pcap)(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
125 uint8_t *packet, size_t len);
126 void (*prepare_close_pcap)(int fd, enum pcap_mode mode);
127 void (*fsync_pcap)(int fd);
130 extern const struct pcap_file_ops pcap_rw_ops;
131 extern const struct pcap_file_ops pcap_sg_ops;
132 extern const struct pcap_file_ops pcap_mm_ops;
134 static inline void pcap_check_magic(uint32_t magic)
136 switch (magic) {
138 case ORIGINAL_TCPDUMP_MAGIC:
139 case NSEC_TCPDUMP_MAGIC:
140 case KUZNETZOV_TCPDUMP_MAGIC:
141 case BORKMANN_TCPDUMP_MAGIC:
143 case ___constant_swab32(ORIGINAL_TCPDUMP_MAGIC):
144 case ___constant_swab32(NSEC_TCPDUMP_MAGIC):
145 case ___constant_swab32(KUZNETZOV_TCPDUMP_MAGIC):
146 case ___constant_swab32(BORKMANN_TCPDUMP_MAGIC):
147 break;
149 default:
150 panic("This file has not a valid pcap header\n");
154 static inline bool pcap_magic_is_swapped(uint32_t magic)
156 bool swapped = false;
158 switch (magic) {
159 case ___constant_swab32(ORIGINAL_TCPDUMP_MAGIC):
160 case ___constant_swab32(NSEC_TCPDUMP_MAGIC):
161 case ___constant_swab32(KUZNETZOV_TCPDUMP_MAGIC):
162 case ___constant_swab32(BORKMANN_TCPDUMP_MAGIC):
163 swapped = true;
166 return swapped;
169 static inline u32 pcap_get_length(pcap_pkthdr_t *phdr, enum pcap_type type)
171 switch (type) {
172 #define CASE_RET_CAPLEN(what, member, swap) \
173 case (what): \
174 return (swap ? ___constant_swab32(phdr->member.caplen) : \
175 phdr->member.caplen)
177 CASE_RET_CAPLEN(DEFAULT, ppo, 0);
178 CASE_RET_CAPLEN(NSEC, ppn, 0);
179 CASE_RET_CAPLEN(KUZNETZOV, ppk, 0);
180 CASE_RET_CAPLEN(BORKMANN, ppb, 0);
182 CASE_RET_CAPLEN(DEFAULT_SWAPPED, ppo, 1);
183 CASE_RET_CAPLEN(NSEC_SWAPPED, ppn, 1);
184 CASE_RET_CAPLEN(KUZNETZOV_SWAPPED, ppk, 1);
185 CASE_RET_CAPLEN(BORKMANN_SWAPPED, ppb, 1);
187 default:
188 bug();
192 static inline void pcap_set_length(pcap_pkthdr_t *phdr, enum pcap_type type, u32 len)
194 switch (type) {
195 #define CASE_SET_CAPLEN(what, member, swap) \
196 case (what): \
197 phdr->member.caplen = (swap ? ___constant_swab32(len) : len); \
198 break
200 CASE_SET_CAPLEN(DEFAULT, ppo, 0);
201 CASE_SET_CAPLEN(NSEC, ppn, 0);
202 CASE_SET_CAPLEN(KUZNETZOV, ppk, 0);
203 CASE_SET_CAPLEN(BORKMANN, ppb, 0);
205 CASE_SET_CAPLEN(DEFAULT_SWAPPED, ppo, 1);
206 CASE_SET_CAPLEN(NSEC_SWAPPED, ppn, 1);
207 CASE_SET_CAPLEN(KUZNETZOV_SWAPPED, ppk, 1);
208 CASE_SET_CAPLEN(BORKMANN_SWAPPED, ppb, 1);
210 default:
211 bug();
215 static inline u32 pcap_get_hdr_length(pcap_pkthdr_t *phdr, enum pcap_type type)
217 switch (type) {
218 #define CASE_RET_HDRLEN(what, member) \
219 case (what): \
220 return sizeof(phdr->member)
222 CASE_RET_HDRLEN(DEFAULT, ppo);
223 CASE_RET_HDRLEN(NSEC, ppn);
224 CASE_RET_HDRLEN(KUZNETZOV, ppk);
225 CASE_RET_HDRLEN(BORKMANN, ppb);
227 CASE_RET_HDRLEN(DEFAULT_SWAPPED, ppo);
228 CASE_RET_HDRLEN(NSEC_SWAPPED, ppn);
229 CASE_RET_HDRLEN(KUZNETZOV_SWAPPED, ppk);
230 CASE_RET_HDRLEN(BORKMANN_SWAPPED, ppb);
232 default:
233 bug();
237 static inline u32 pcap_get_total_length(pcap_pkthdr_t *phdr, enum pcap_type type)
239 switch (type) {
240 #define CASE_RET_TOTLEN(what, member, swap) \
241 case (what): \
242 return ((swap ? ___constant_swab32(phdr->member.caplen) : \
243 phdr->member.caplen) + sizeof(phdr->member))
245 CASE_RET_TOTLEN(DEFAULT, ppo, 0);
246 CASE_RET_TOTLEN(NSEC, ppn, 0);
247 CASE_RET_TOTLEN(KUZNETZOV, ppk, 0);
248 CASE_RET_TOTLEN(BORKMANN, ppb, 0);
250 CASE_RET_TOTLEN(DEFAULT_SWAPPED, ppo, 1);
251 CASE_RET_TOTLEN(NSEC_SWAPPED, ppn, 1);
252 CASE_RET_TOTLEN(KUZNETZOV_SWAPPED, ppk, 1);
253 CASE_RET_TOTLEN(BORKMANN_SWAPPED, ppb, 1);
255 default:
256 bug();
260 static inline void tpacket_hdr_to_pcap_pkthdr(struct tpacket2_hdr *thdr,
261 struct sockaddr_ll *sll,
262 pcap_pkthdr_t *phdr,
263 enum pcap_type type)
265 switch (type) {
266 case DEFAULT:
267 phdr->ppo.ts.tv_sec = thdr->tp_sec;
268 phdr->ppo.ts.tv_usec = thdr->tp_nsec / 1000;
269 phdr->ppo.caplen = thdr->tp_snaplen;
270 phdr->ppo.len = thdr->tp_len;
271 break;
273 case DEFAULT_SWAPPED:
274 phdr->ppo.ts.tv_sec = ___constant_swab32(thdr->tp_sec);
275 phdr->ppo.ts.tv_usec = ___constant_swab32(thdr->tp_nsec / 1000);
276 phdr->ppo.caplen = ___constant_swab32(thdr->tp_snaplen);
277 phdr->ppo.len = ___constant_swab32(thdr->tp_len);
278 break;
280 case NSEC:
281 phdr->ppn.ts.tv_sec = thdr->tp_sec;
282 phdr->ppn.ts.tv_nsec = thdr->tp_nsec;
283 phdr->ppn.caplen = thdr->tp_snaplen;
284 phdr->ppn.len = thdr->tp_len;
285 break;
287 case NSEC_SWAPPED:
288 phdr->ppn.ts.tv_sec = ___constant_swab32(thdr->tp_sec);
289 phdr->ppn.ts.tv_nsec = ___constant_swab32(thdr->tp_nsec);
290 phdr->ppn.caplen = ___constant_swab32(thdr->tp_snaplen);
291 phdr->ppn.len = ___constant_swab32(thdr->tp_len);
292 break;
294 case KUZNETZOV:
295 phdr->ppk.ts.tv_sec = thdr->tp_sec;
296 phdr->ppk.ts.tv_usec = thdr->tp_nsec / 1000;
297 phdr->ppk.caplen = thdr->tp_snaplen;
298 phdr->ppk.len = thdr->tp_len;
299 phdr->ppk.ifindex = sll->sll_ifindex;
300 phdr->ppk.protocol = sll->sll_protocol;
301 phdr->ppk.pkttype = sll->sll_pkttype;
302 break;
304 case KUZNETZOV_SWAPPED:
305 phdr->ppk.ts.tv_sec = ___constant_swab32(thdr->tp_sec);
306 phdr->ppk.ts.tv_usec = ___constant_swab32(thdr->tp_nsec / 1000);
307 phdr->ppk.caplen = ___constant_swab32(thdr->tp_snaplen);
308 phdr->ppk.len = ___constant_swab32(thdr->tp_len);
309 phdr->ppk.ifindex = ___constant_swab32((u32) sll->sll_ifindex);
310 phdr->ppk.protocol = ___constant_swab16(sll->sll_protocol);
311 phdr->ppk.pkttype = sll->sll_pkttype;
312 break;
314 case BORKMANN:
315 phdr->ppb.ts.tv_sec = thdr->tp_sec;
316 phdr->ppb.ts.tv_nsec = thdr->tp_nsec;
317 phdr->ppb.caplen = thdr->tp_snaplen;
318 phdr->ppb.len = thdr->tp_len;
319 phdr->ppb.ifindex = (u32) sll->sll_ifindex;
320 phdr->ppb.protocol = sll->sll_protocol;
321 phdr->ppb.hatype = sll->sll_hatype;
322 phdr->ppb.pkttype = sll->sll_pkttype;
323 break;
325 case BORKMANN_SWAPPED:
326 phdr->ppb.ts.tv_sec = ___constant_swab32(thdr->tp_sec);
327 phdr->ppb.ts.tv_nsec = ___constant_swab32(thdr->tp_nsec);
328 phdr->ppb.caplen = ___constant_swab32(thdr->tp_snaplen);
329 phdr->ppb.len = ___constant_swab32(thdr->tp_len);
330 phdr->ppb.ifindex = ___constant_swab32((u32) sll->sll_ifindex);
331 phdr->ppb.protocol = ___constant_swab16(sll->sll_protocol);
332 phdr->ppb.hatype = sll->sll_hatype;
333 phdr->ppb.pkttype = sll->sll_pkttype;
334 break;
336 default:
337 bug();
341 static inline void pcap_pkthdr_to_tpacket_hdr(pcap_pkthdr_t *phdr,
342 enum pcap_type type,
343 struct tpacket2_hdr *thdr,
344 struct sockaddr_ll *sll)
346 switch (type) {
347 case DEFAULT:
348 thdr->tp_sec = phdr->ppo.ts.tv_sec;
349 thdr->tp_nsec = phdr->ppo.ts.tv_usec * 1000;
350 thdr->tp_snaplen = phdr->ppo.caplen;
351 thdr->tp_len = phdr->ppo.len;
352 break;
354 case DEFAULT_SWAPPED:
355 thdr->tp_sec = ___constant_swab32(phdr->ppo.ts.tv_sec);
356 thdr->tp_nsec = ___constant_swab32(phdr->ppo.ts.tv_usec) * 1000;
357 thdr->tp_snaplen = ___constant_swab32(phdr->ppo.caplen);
358 thdr->tp_len = ___constant_swab32(phdr->ppo.len);
359 break;
361 case NSEC:
362 thdr->tp_sec = phdr->ppn.ts.tv_sec;
363 thdr->tp_nsec = phdr->ppn.ts.tv_nsec;
364 thdr->tp_snaplen = phdr->ppn.caplen;
365 thdr->tp_len = phdr->ppn.len;
366 break;
368 case NSEC_SWAPPED:
369 thdr->tp_sec = ___constant_swab32(phdr->ppn.ts.tv_sec);
370 thdr->tp_nsec = ___constant_swab32(phdr->ppn.ts.tv_nsec);
371 thdr->tp_snaplen = ___constant_swab32(phdr->ppn.caplen);
372 thdr->tp_len = ___constant_swab32(phdr->ppn.len);
373 break;
375 case KUZNETZOV:
376 thdr->tp_sec = phdr->ppk.ts.tv_sec;
377 thdr->tp_nsec = phdr->ppk.ts.tv_usec * 1000;
378 thdr->tp_snaplen = phdr->ppk.caplen;
379 thdr->tp_len = phdr->ppk.len;
380 break;
382 case KUZNETZOV_SWAPPED:
383 thdr->tp_sec = ___constant_swab32(phdr->ppk.ts.tv_sec);
384 thdr->tp_nsec = ___constant_swab32(phdr->ppk.ts.tv_usec) * 1000;
385 thdr->tp_snaplen = ___constant_swab32(phdr->ppk.caplen);
386 thdr->tp_len = ___constant_swab32(phdr->ppk.len);
387 break;
389 case BORKMANN:
390 thdr->tp_sec = phdr->ppb.ts.tv_sec;
391 thdr->tp_nsec = phdr->ppb.ts.tv_nsec;
392 thdr->tp_snaplen = phdr->ppb.caplen;
393 thdr->tp_len = phdr->ppb.len;
394 break;
396 case BORKMANN_SWAPPED:
397 thdr->tp_sec = ___constant_swab32(phdr->ppb.ts.tv_sec);
398 thdr->tp_nsec = ___constant_swab32(phdr->ppb.ts.tv_nsec);
399 thdr->tp_snaplen = ___constant_swab32(phdr->ppb.caplen);
400 thdr->tp_len = ___constant_swab32(phdr->ppb.len);
401 break;
403 default:
404 bug();
408 #define FEATURE_UNKNOWN (0 << 0)
409 #define FEATURE_TIMEVAL_MS (1 << 0)
410 #define FEATURE_TIMEVAL_NS (1 << 1)
411 #define FEATURE_LEN (1 << 2)
412 #define FEATURE_CAPLEN (1 << 3)
413 #define FEATURE_IFINDEX (1 << 4)
414 #define FEATURE_PROTO (1 << 5)
415 #define FEATURE_HATYPE (1 << 6)
416 #define FEATURE_PKTTYPE (1 << 7)
418 struct pcap_magic_type {
419 const uint32_t magic;
420 const char *desc;
421 const uint16_t features;
424 static const struct pcap_magic_type pcap_magic_types[] __maybe_unused = {
426 .magic = ORIGINAL_TCPDUMP_MAGIC,
427 .desc = "tcpdump-capable pcap",
428 .features = FEATURE_TIMEVAL_MS |
429 FEATURE_LEN |
430 FEATURE_CAPLEN,
431 }, {
432 .magic = NSEC_TCPDUMP_MAGIC,
433 .desc = "tcpdump-capable pcap with ns resolution",
434 .features = FEATURE_TIMEVAL_NS |
435 FEATURE_LEN |
436 FEATURE_CAPLEN,
437 }, {
438 .magic = KUZNETZOV_TCPDUMP_MAGIC,
439 .desc = "Alexey Kuznetzov's pcap",
440 .features = FEATURE_TIMEVAL_MS |
441 FEATURE_LEN |
442 FEATURE_CAPLEN |
443 FEATURE_IFINDEX |
444 FEATURE_PROTO |
445 FEATURE_PKTTYPE,
446 }, {
447 .magic = BORKMANN_TCPDUMP_MAGIC,
448 .desc = "netsniff-ng pcap",
449 .features = FEATURE_TIMEVAL_NS |
450 FEATURE_LEN |
451 FEATURE_CAPLEN |
452 FEATURE_IFINDEX |
453 FEATURE_PROTO |
454 FEATURE_HATYPE |
455 FEATURE_PKTTYPE,
459 static inline void pcap_dump_type_features(void)
461 int i;
463 for (i = 0; i < array_size(pcap_magic_types); ++i) {
464 printf("%s:\n", pcap_magic_types[i].desc);
465 printf(" magic: 0x%x (swapped: 0x%x)\n",
466 pcap_magic_types[i].magic,
467 ___constant_swab32(pcap_magic_types[i].magic));
468 printf(" features:\n");
470 if (pcap_magic_types[i].features == FEATURE_UNKNOWN) {
471 printf(" unknown\n");
472 continue;
475 if (pcap_magic_types[i].features & FEATURE_TIMEVAL_MS)
476 printf(" timeval in us\n");
477 if (pcap_magic_types[i].features & FEATURE_TIMEVAL_NS)
478 printf(" timeval in ns\n");
479 if (pcap_magic_types[i].features & FEATURE_LEN)
480 printf(" packet length\n");
481 if (pcap_magic_types[i].features & FEATURE_CAPLEN)
482 printf(" packet cap-length\n");
483 if (pcap_magic_types[i].features & FEATURE_IFINDEX)
484 printf(" packet ifindex\n");
485 if (pcap_magic_types[i].features & FEATURE_PROTO)
486 printf(" packet protocol\n");
487 if (pcap_magic_types[i].features & FEATURE_HATYPE)
488 printf(" hardware type\n");
489 if (pcap_magic_types[i].features & FEATURE_PKTTYPE)
490 printf(" packet type\n");
494 static const char *pcap_ops_group_to_str[] __maybe_unused = {
495 [PCAP_OPS_RW] = "rw",
496 [PCAP_OPS_SG] = "sg",
497 [PCAP_OPS_MM] = "mm",
500 static const struct pcap_file_ops *pcap_ops[] __maybe_unused = {
501 [PCAP_OPS_RW] = &pcap_rw_ops,
502 [PCAP_OPS_SG] = &pcap_sg_ops,
503 [PCAP_OPS_MM] = &pcap_mm_ops,
506 static inline void pcap_prepare_header(struct pcap_filehdr *hdr, uint32_t magic,
507 uint32_t linktype, int32_t thiszone,
508 uint32_t snaplen)
510 bool swapped = pcap_magic_is_swapped(magic);
512 hdr->magic = magic;
513 hdr->version_major = swapped ? ___constant_swab16(PCAP_VERSION_MAJOR) : PCAP_VERSION_MAJOR;
514 hdr->version_minor = swapped ? ___constant_swab16(PCAP_VERSION_MINOR) : PCAP_VERSION_MINOR;
515 hdr->thiszone = swapped ? ___constant_swab32(thiszone) : thiszone;
516 hdr->sigfigs = 0;
517 hdr->snaplen = swapped ? ___constant_swab32(snaplen) : snaplen;
518 hdr->linktype = swapped ? ___constant_swab32(linktype) : linktype;
521 static inline void pcap_validate_header(const struct pcap_filehdr *hdr)
523 pcap_check_magic(hdr->magic);
525 switch (hdr->linktype) {
526 case LINKTYPE_EN10MB:
527 case LINKTYPE_IEEE802_11:
528 case ___constant_swab32(LINKTYPE_EN10MB):
529 case ___constant_swab32(LINKTYPE_IEEE802_11):
530 break;
531 default:
532 panic("This file has not a valid pcap header\n");
535 if (unlikely(hdr->version_major != PCAP_VERSION_MAJOR) &&
536 ___constant_swab16(hdr->version_major) != PCAP_VERSION_MAJOR)
537 panic("This file has not a valid pcap header\n");
538 if (unlikely(hdr->version_minor != PCAP_VERSION_MINOR) &&
539 ___constant_swab16(hdr->version_minor) != PCAP_VERSION_MINOR)
540 panic("This file has not a valid pcap header\n");
543 static int pcap_generic_pull_fhdr(int fd, uint32_t *magic,
544 uint32_t *linktype) __maybe_unused;
546 static int pcap_generic_pull_fhdr(int fd, uint32_t *magic, uint32_t *linktype)
548 ssize_t ret;
549 struct pcap_filehdr hdr;
551 ret = read(fd, &hdr, sizeof(hdr));
552 if (unlikely(ret != sizeof(hdr)))
553 return -EIO;
555 pcap_validate_header(&hdr);
557 *magic = hdr.magic;
558 *linktype = hdr.linktype;
560 return 0;
563 static int pcap_generic_push_fhdr(int fd, uint32_t magic,
564 uint32_t linktype) __maybe_unused;
566 static int pcap_generic_push_fhdr(int fd, uint32_t magic, uint32_t linktype)
568 ssize_t ret;
569 struct pcap_filehdr hdr;
571 memset(&hdr, 0, sizeof(hdr));
573 pcap_prepare_header(&hdr, magic, linktype, 0, PCAP_DEFAULT_SNAPSHOT_LEN);
575 ret = write_or_die(fd, &hdr, sizeof(hdr));
576 if (unlikely(ret != sizeof(hdr)))
577 panic("Failed to write pkt file header!\n");
579 return 0;
582 #endif /* PCAP_IO_H */