dissector: make pkttypes const
[netsniff-ng.git] / pcap.h
blob23afd972aa1ce184e76c596fa2a5754e63efce96
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 } 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,
101 enum pcap_ops_groups {
102 PCAP_OPS_RW = 0,
103 PCAP_OPS_SG,
104 PCAP_OPS_MM,
107 enum pcap_mode {
108 PCAP_MODE_RD = 0,
109 PCAP_MODE_WR,
112 struct pcap_file_ops {
113 int (*pull_fhdr_pcap)(int fd, uint32_t *magic, uint32_t *linktype);
114 int (*push_fhdr_pcap)(int fd, uint32_t magic, uint32_t linktype);
115 int (*prepare_access_pcap)(int fd, enum pcap_mode mode, bool jumbo);
116 ssize_t (*write_pcap)(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
117 const uint8_t *packet, size_t len);
118 ssize_t (*read_pcap)(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
119 uint8_t *packet, size_t len);
120 void (*prepare_close_pcap)(int fd, enum pcap_mode mode);
121 void (*fsync_pcap)(int fd);
124 extern const struct pcap_file_ops pcap_rw_ops;
125 extern const struct pcap_file_ops pcap_sg_ops;
126 extern const struct pcap_file_ops pcap_mm_ops;
128 static inline void pcap_check_magic(uint32_t magic)
130 switch (magic) {
131 case DEFAULT:
132 case NSEC:
133 case KUZNETZOV:
134 case BORKMANN:
135 break;
136 default:
137 panic("This file has not a valid pcap header\n");
141 static inline u32 pcap_get_length(pcap_pkthdr_t *phdr, enum pcap_type type)
143 switch (type) {
144 #define CASE_RET_CAPLEN(what, member) \
145 case (what): \
146 return phdr->member.caplen
147 CASE_RET_CAPLEN(DEFAULT, ppo);
148 CASE_RET_CAPLEN(NSEC, ppn);
149 CASE_RET_CAPLEN(KUZNETZOV, ppk);
150 CASE_RET_CAPLEN(BORKMANN, ppb);
151 default:
152 bug();
156 static inline void pcap_set_length(pcap_pkthdr_t *phdr, enum pcap_type type, u32 len)
158 switch (type) {
159 #define CASE_SET_CAPLEN(what, member) \
160 case (what): \
161 phdr->member.caplen = len; \
162 break
163 CASE_SET_CAPLEN(DEFAULT, ppo);
164 CASE_SET_CAPLEN(NSEC, ppn);
165 CASE_SET_CAPLEN(KUZNETZOV, ppk);
166 CASE_SET_CAPLEN(BORKMANN, ppb);
167 default:
168 bug();
172 static inline u32 pcap_get_hdr_length(pcap_pkthdr_t *phdr, enum pcap_type type)
174 switch (type) {
175 #define CASE_RET_HDRLEN(what, member) \
176 case (what): \
177 return sizeof(phdr->member)
178 CASE_RET_HDRLEN(DEFAULT, ppo);
179 CASE_RET_HDRLEN(NSEC, ppn);
180 CASE_RET_HDRLEN(KUZNETZOV, ppk);
181 CASE_RET_HDRLEN(BORKMANN, ppb);
182 default:
183 bug();
187 static inline u32 pcap_get_total_length(pcap_pkthdr_t *phdr, enum pcap_type type)
189 switch (type) {
190 #define CASE_RET_TOTLEN(what, member) \
191 case (what): \
192 return phdr->member.caplen + sizeof(phdr->member)
193 CASE_RET_TOTLEN(DEFAULT, ppo);
194 CASE_RET_TOTLEN(NSEC, ppn);
195 CASE_RET_TOTLEN(KUZNETZOV, ppk);
196 CASE_RET_TOTLEN(BORKMANN, ppb);
197 default:
198 bug();
202 static inline void tpacket_hdr_to_pcap_pkthdr(struct tpacket2_hdr *thdr,
203 struct sockaddr_ll *sll,
204 pcap_pkthdr_t *phdr,
205 enum pcap_type type)
207 switch (type) {
208 case DEFAULT:
209 phdr->ppo.ts.tv_sec = thdr->tp_sec;
210 phdr->ppo.ts.tv_usec = thdr->tp_nsec / 1000;
211 phdr->ppo.caplen = thdr->tp_snaplen;
212 phdr->ppo.len = thdr->tp_len;
213 break;
215 case NSEC:
216 phdr->ppn.ts.tv_sec = thdr->tp_sec;
217 phdr->ppn.ts.tv_nsec = thdr->tp_nsec;
218 phdr->ppn.caplen = thdr->tp_snaplen;
219 phdr->ppn.len = thdr->tp_len;
220 break;
222 case KUZNETZOV:
223 phdr->ppk.ts.tv_sec = thdr->tp_sec;
224 phdr->ppk.ts.tv_usec = thdr->tp_nsec / 1000;
225 phdr->ppk.caplen = thdr->tp_snaplen;
226 phdr->ppk.len = thdr->tp_len;
227 phdr->ppk.ifindex = sll->sll_ifindex;
228 phdr->ppk.protocol = sll->sll_protocol;
229 phdr->ppk.pkttype = sll->sll_pkttype;
230 break;
232 case BORKMANN:
233 phdr->ppb.ts.tv_sec = thdr->tp_sec;
234 phdr->ppb.ts.tv_nsec = thdr->tp_nsec;
235 phdr->ppb.caplen = thdr->tp_snaplen;
236 phdr->ppb.len = thdr->tp_len;
237 phdr->ppb.ifindex = (u32) sll->sll_ifindex;
238 phdr->ppb.protocol = sll->sll_protocol;
239 phdr->ppb.hatype = sll->sll_hatype;
240 phdr->ppb.pkttype = sll->sll_pkttype;
241 break;
243 default:
244 bug();
248 static inline void pcap_pkthdr_to_tpacket_hdr(pcap_pkthdr_t *phdr,
249 enum pcap_type type,
250 struct tpacket2_hdr *thdr,
251 struct sockaddr_ll *sll)
253 switch (type) {
254 case DEFAULT:
255 thdr->tp_sec = phdr->ppo.ts.tv_sec;
256 thdr->tp_nsec = phdr->ppo.ts.tv_usec * 1000;
257 thdr->tp_snaplen = phdr->ppo.caplen;
258 thdr->tp_len = phdr->ppo.len;
259 break;
261 case NSEC:
262 thdr->tp_sec = phdr->ppn.ts.tv_sec;
263 thdr->tp_nsec = phdr->ppn.ts.tv_nsec;
264 thdr->tp_snaplen = phdr->ppn.caplen;
265 thdr->tp_len = phdr->ppn.len;
266 break;
268 case KUZNETZOV:
269 thdr->tp_sec = phdr->ppk.ts.tv_sec;
270 thdr->tp_nsec = phdr->ppk.ts.tv_usec * 1000;
271 thdr->tp_snaplen = phdr->ppk.caplen;
272 thdr->tp_len = phdr->ppk.len;
273 sll->sll_ifindex = phdr->ppk.ifindex;
274 sll->sll_protocol = phdr->ppk.protocol;
275 sll->sll_pkttype = phdr->ppk.pkttype;
276 break;
278 case BORKMANN:
279 thdr->tp_sec = phdr->ppb.ts.tv_sec;
280 thdr->tp_nsec = phdr->ppb.ts.tv_nsec;
281 thdr->tp_snaplen = phdr->ppb.caplen;
282 thdr->tp_len = phdr->ppb.len;
283 sll->sll_ifindex = (int) phdr->ppb.ifindex;
284 sll->sll_protocol = phdr->ppb.protocol;
285 sll->sll_hatype = phdr->ppb.hatype;
286 sll->sll_pkttype = phdr->ppb.pkttype;
287 break;
289 default:
290 bug();
294 #define FEATURE_UNKNOWN (0 << 0)
295 #define FEATURE_TIMEVAL_MS (1 << 0)
296 #define FEATURE_TIMEVAL_NS (1 << 1)
297 #define FEATURE_LEN (1 << 2)
298 #define FEATURE_CAPLEN (1 << 3)
299 #define FEATURE_IFINDEX (1 << 4)
300 #define FEATURE_PROTO (1 << 5)
301 #define FEATURE_HATYPE (1 << 6)
302 #define FEATURE_PKTTYPE (1 << 7)
304 struct pcap_magic_type {
305 uint32_t magic;
306 char *desc;
307 uint16_t features;
310 static const struct pcap_magic_type const pcap_magic_types[] __maybe_unused = {
312 .magic = ORIGINAL_TCPDUMP_MAGIC,
313 .desc = "tcpdump-capable pcap",
314 .features = FEATURE_TIMEVAL_MS |
315 FEATURE_LEN |
316 FEATURE_CAPLEN,
317 }, {
318 .magic = NSEC_TCPDUMP_MAGIC,
319 .desc = "tcpdump-capable pcap with ns resolution",
320 .features = FEATURE_TIMEVAL_NS |
321 FEATURE_LEN |
322 FEATURE_CAPLEN,
323 }, {
324 .magic = KUZNETZOV_TCPDUMP_MAGIC,
325 .desc = "Alexey Kuznetzov's pcap",
326 .features = FEATURE_TIMEVAL_MS |
327 FEATURE_LEN |
328 FEATURE_CAPLEN |
329 FEATURE_IFINDEX |
330 FEATURE_PROTO |
331 FEATURE_PKTTYPE,
332 }, {
333 .magic = BORKMANN_TCPDUMP_MAGIC,
334 .desc = "netsniff-ng pcap",
335 .features = FEATURE_TIMEVAL_NS |
336 FEATURE_LEN |
337 FEATURE_CAPLEN |
338 FEATURE_IFINDEX |
339 FEATURE_PROTO |
340 FEATURE_HATYPE |
341 FEATURE_PKTTYPE,
345 static inline void pcap_dump_type_features(void)
347 int i;
349 for (i = 0; i < array_size(pcap_magic_types); ++i) {
350 printf("%s:\n", pcap_magic_types[i].desc);
351 printf(" magic: 0x%x\n", pcap_magic_types[i].magic);
352 printf(" features:\n");
354 if (pcap_magic_types[i].features == FEATURE_UNKNOWN) {
355 printf(" unknown\n");
356 continue;
359 if (pcap_magic_types[i].features & FEATURE_TIMEVAL_MS)
360 printf(" timeval in us\n");
361 if (pcap_magic_types[i].features & FEATURE_TIMEVAL_NS)
362 printf(" timeval in ns\n");
363 if (pcap_magic_types[i].features & FEATURE_LEN)
364 printf(" packet length\n");
365 if (pcap_magic_types[i].features & FEATURE_CAPLEN)
366 printf(" packet cap-length\n");
367 if (pcap_magic_types[i].features & FEATURE_IFINDEX)
368 printf(" packet ifindex\n");
369 if (pcap_magic_types[i].features & FEATURE_PROTO)
370 printf(" packet protocol\n");
371 if (pcap_magic_types[i].features & FEATURE_HATYPE)
372 printf(" hardware type\n");
373 if (pcap_magic_types[i].features & FEATURE_PKTTYPE)
374 printf(" packet type\n");
378 static const char *pcap_ops_group_to_str[] __maybe_unused = {
379 [PCAP_OPS_RW] = "rw",
380 [PCAP_OPS_SG] = "sg",
381 [PCAP_OPS_MM] = "mm",
384 static const struct pcap_file_ops const *pcap_ops[] __maybe_unused = {
385 [PCAP_OPS_RW] = &pcap_rw_ops,
386 [PCAP_OPS_SG] = &pcap_sg_ops,
387 [PCAP_OPS_MM] = &pcap_mm_ops,
390 static inline void pcap_prepare_header(struct pcap_filehdr *hdr, uint32_t magic,
391 uint32_t linktype, int32_t thiszone,
392 uint32_t snaplen)
394 hdr->magic = magic;
395 hdr->version_major = PCAP_VERSION_MAJOR;
396 hdr->version_minor = PCAP_VERSION_MINOR;
397 hdr->thiszone = thiszone;
398 hdr->sigfigs = 0;
399 hdr->snaplen = snaplen;
400 hdr->linktype = linktype;
403 static inline void pcap_validate_header(const struct pcap_filehdr *hdr)
405 pcap_check_magic(hdr->magic);
407 switch (hdr->linktype) {
408 case LINKTYPE_EN10MB:
409 case LINKTYPE_IEEE802_11:
410 break;
411 default:
412 panic("This file has not a valid pcap header\n");
415 if (unlikely(hdr->version_major != PCAP_VERSION_MAJOR))
416 panic("This file has not a valid pcap header\n");
417 if (unlikely(hdr->version_minor != PCAP_VERSION_MINOR))
418 panic("This file has not a valid pcap header\n");
421 static int pcap_generic_pull_fhdr(int fd, uint32_t *magic,
422 uint32_t *linktype) __maybe_unused;
424 static int pcap_generic_pull_fhdr(int fd, uint32_t *magic, uint32_t *linktype)
426 ssize_t ret;
427 struct pcap_filehdr hdr;
429 ret = read(fd, &hdr, sizeof(hdr));
430 if (unlikely(ret != sizeof(hdr)))
431 return -EIO;
433 pcap_validate_header(&hdr);
435 *magic = hdr.magic;
436 *linktype = hdr.linktype;
438 return 0;
441 static int pcap_generic_push_fhdr(int fd, uint32_t magic,
442 uint32_t linktype) __maybe_unused;
444 static int pcap_generic_push_fhdr(int fd, uint32_t magic, uint32_t linktype)
446 ssize_t ret;
447 struct pcap_filehdr hdr;
449 memset(&hdr, 0, sizeof(hdr));
451 pcap_prepare_header(&hdr, magic, linktype, 0, PCAP_DEFAULT_SNAPSHOT_LEN);
453 ret = write_or_die(fd, &hdr, sizeof(hdr));
454 if (unlikely(ret != sizeof(hdr)))
455 panic("Failed to write pkt file header!\n");
457 return 0;
460 #endif /* PCAP_H */