proto_none: minor: make hex/chr conform with the rest
[netsniff-ng.git] / pcap.h
blob8c9fa50e1fce3d11e2ba44fedc0a92b47374e0b2
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * By Daniel Borkmann <daniel@netsniff-ng.org>
4 * Copyright 2009 - 2013 Daniel Borkmann.
5 * Copyright 2010 Emmanuel Roullit.
6 * Subject to the GPL, version 2.
7 */
9 #ifndef PCAP_H
10 #define PCAP_H
12 #include <unistd.h>
13 #include <stdint.h>
14 #include <stdbool.h>
15 #include <errno.h>
16 #include <sys/time.h>
17 #include <linux/if_packet.h>
19 #include "built_in.h"
20 #include "die.h"
21 #include "xio.h"
23 #define TCPDUMP_MAGIC 0xa1b2c3d4
24 #define ORIGINAL_TCPDUMP_MAGIC TCPDUMP_MAGIC
25 #define NSEC_TCPDUMP_MAGIC 0xa1b23c4d
26 #define KUZNETZOV_TCPDUMP_MAGIC 0xa1b2cd34
27 #define BORKMANN_TCPDUMP_MAGIC 0xa1e2cb12
29 #define PCAP_VERSION_MAJOR 2
30 #define PCAP_VERSION_MINOR 4
31 #define PCAP_DEFAULT_SNAPSHOT_LEN 65535
33 #define LINKTYPE_EN10MB 1 /* Ethernet (10Mb) */
34 #define LINKTYPE_IEEE802_11 105 /* IEEE 802.11 wireless */
36 struct pcap_filehdr {
37 uint32_t magic;
38 uint16_t version_major;
39 uint16_t version_minor;
40 int32_t thiszone;
41 uint32_t sigfigs;
42 uint32_t snaplen;
43 uint32_t linktype;
46 struct pcap_timeval {
47 int32_t tv_sec;
48 int32_t tv_usec;
51 struct pcap_timeval_ns {
52 int32_t tv_sec;
53 int32_t tv_nsec;
56 struct pcap_pkthdr {
57 struct pcap_timeval ts;
58 uint32_t caplen;
59 uint32_t len;
62 struct pcap_pkthdr_ns {
63 struct pcap_timeval_ns ts;
64 uint32_t caplen;
65 uint32_t len;
68 struct pcap_pkthdr_kuz {
69 struct pcap_timeval ts;
70 uint32_t caplen;
71 uint32_t len;
72 int ifindex;
73 uint16_t protocol;
74 uint8_t pkttype;
77 struct pcap_pkthdr_bkm {
78 struct pcap_timeval_ns ts;
79 uint32_t caplen;
80 uint32_t len;
81 uint32_t ifindex;
82 uint16_t protocol;
83 uint8_t hatype;
84 uint8_t pkttype;
87 typedef union {
88 struct pcap_pkthdr ppo;
89 struct pcap_pkthdr_ns ppn;
90 struct pcap_pkthdr_kuz ppk;
91 struct pcap_pkthdr_bkm ppb;
92 uint8_t raw;
93 } pcap_pkthdr_t;
95 enum pcap_type {
96 DEFAULT = ORIGINAL_TCPDUMP_MAGIC,
97 NSEC = NSEC_TCPDUMP_MAGIC,
98 KUZNETZOV = KUZNETZOV_TCPDUMP_MAGIC,
99 BORKMANN = BORKMANN_TCPDUMP_MAGIC,
101 DEFAULT_SWAPPED = ___constant_swab32(ORIGINAL_TCPDUMP_MAGIC),
102 NSEC_SWAPPED = ___constant_swab32(NSEC_TCPDUMP_MAGIC),
103 KUZNETZOV_SWAPPED = ___constant_swab32(KUZNETZOV_TCPDUMP_MAGIC),
104 BORKMANN_SWAPPED = ___constant_swab32(BORKMANN_TCPDUMP_MAGIC),
107 enum pcap_ops_groups {
108 PCAP_OPS_RW = 0,
109 PCAP_OPS_SG,
110 PCAP_OPS_MM,
113 enum pcap_mode {
114 PCAP_MODE_RD = 0,
115 PCAP_MODE_WR,
118 struct pcap_file_ops {
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 uint32_t magic;
420 char *desc;
421 uint16_t features;
424 static const struct pcap_magic_type const 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 const *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_H */