]> The Tcpdump Group git mirrors - tcpdump/blob - print-pflog.c
CI: Add warning exemptions for Sun C (suncc-5.14) on Solaris 10
[tcpdump] / print-pflog.c
1 /*
2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996
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
22 /* \summary: *BSD/Darwin packet filter log file printer */
23
24 #include <config.h>
25
26 #include <limits.h>
27
28 #include "netdissect-stdinc.h"
29
30 #define ND_LONGJMP_FROM_TCHECK
31 #include "netdissect.h"
32 #include "extract.h"
33 #include "af.h"
34 #include "addrtostr.h"
35
36 /*
37 * pflog headers, at least as they exist now.
38 */
39 #define PFLOG_IFNAMSIZ 16
40 #define PFLOG_RULESET_NAME_SIZE 16
41
42 struct pf_addr {
43 union {
44 nd_ipv4 v4;
45 nd_ipv6 v6;
46 } pfa; /* 128-bit address */
47 #define v4 pfa.v4
48 #define v6 pfa.v6
49 };
50
51 /*
52 * This header is:
53 *
54 * 61 bytes long on NetBSD, DragonFly BSD. and Darwin;
55 * 84 bytes lon on OpenBSD;
56 * 72 bytes long on FreeBSD;
57 *
58 * which, unfortunately, does not allow us to distinguish, based on
59 * the header length, between the three OSes listed as having 61-byte
60 * headers. As the action values differ between them, this makes it
61 * impossible to correctly dissect the reason values that differ
62 * between NetBSD and Darwin (reason value 15) without having some
63 * way to explicitly tell tcpdump what to do.
64 *
65 * (We could, I guess, label reason value 15 as
66 * "state-locked (NetBSD)/dummynet (macOS etc.)" or something such as
67 * that.)
68 */
69 struct pfloghdr {
70 nd_uint8_t length;
71 nd_uint8_t af;
72 nd_uint8_t action;
73 nd_uint8_t reason;
74 char ifname[PFLOG_IFNAMSIZ];
75 char ruleset[PFLOG_RULESET_NAME_SIZE];
76 nd_uint32_t rulenr;
77 nd_uint32_t subrulenr;
78 nd_uint32_t uid;
79 nd_int32_t pid;
80 nd_uint32_t rule_uid;
81 nd_int32_t rule_pid;
82 nd_uint8_t dir;
83 union {
84 struct pflog_openbsd_only {
85 nd_uint8_t rewritten;
86 nd_uint8_t naf;
87 nd_uint8_t pad[1];
88 struct pf_addr saddr;
89 struct pf_addr daddr;
90 nd_uint16_t sport;
91 nd_uint16_t dport;
92 } openbsd;
93 struct pflog_freebsd_only {
94 nd_uint8_t pad[3];
95 nd_uint32_t ridentifier;
96 nd_uint8_t reserve;
97 } freebsd;
98 } u;
99 };
100
101 /*
102 * FreeBSD header length.
103 */
104 #define PFLOG_HEADER_LEN_FREEBSD 69
105
106 /*
107 * OpenBSD header length.
108 */
109 #define PFLOG_HEADER_LEN_OPENBSD 100
110
111 /*
112 * DragonFly BSD, NetBSD and Darwin header length.
113 * Older versions of FreeBSD and OpenBSD may have used this
114 * as well.
115 *
116 * Unfortunately, this means we can't distinguish between Darwin, NetBSD,
117 * and DragonFly BSD based on the header length.
118 */
119 #define PFLOG_HEADER_LEN_OTHER 61
120
121 /*
122 * These are the minimum and maximum pflog header lengths.
123 */
124 #define MIN_PFLOG_HDRLEN 61
125 #define MAX_PFLOG_HDRLEN 100
126
127 /*
128 * Reason values.
129 */
130 #define PFRES_MATCH 0
131 #define PFRES_BADOFF 1
132 #define PFRES_FRAG 2
133 #define PFRES_SHORT 3
134 #define PFRES_NORM 4
135 #define PFRES_MEMORY 5
136 #define PFRES_TS 6
137 #define PFRES_CONGEST 7
138 #define PFRES_IPOPTIONS 8
139 #define PFRES_PROTCKSUM 9
140 #define PFRES_BADSTATE 10
141 #define PFRES_STATEINS 11
142 #define PFRES_MAXSTATES 12
143 #define PFRES_SRCLIMIT 13
144 #define PFRES_SYNPROXY 14
145
146 /* FreeBSD */
147 #define PFRES_MAPFAILED 15
148
149 /* OpenBSD */
150 #define PFRES_TRANSLATE 15
151 #define PFRES_NOROUTE 16
152
153 /* NetBSD/Darwin */
154 #define PFRES_STATELOCKED_DUMMYNET 15 /* STATELOCKED on NetBSD, DUMMYNET on Darwin */
155 #define PFRES_INVPORT 16 /* INVPORT on Darwin */
156
157 static const struct tok pf_reasons_freebsd[] = {
158 { PFRES_MATCH, "0(match)" },
159 { PFRES_BADOFF, "1(bad-offset)" },
160 { PFRES_FRAG, "2(fragment)" },
161 { PFRES_SHORT, "3(short)" },
162 { PFRES_NORM, "4(normalize)" },
163 { PFRES_MEMORY, "5(memory)" },
164 { PFRES_TS, "6(bad-timestamp)" },
165 { PFRES_CONGEST, "7(congestion)" },
166 { PFRES_IPOPTIONS, "8(ip-option)" },
167 { PFRES_PROTCKSUM, "9(proto-cksum)" },
168 { PFRES_BADSTATE, "10(state-mismatch)" },
169 { PFRES_STATEINS, "11(state-insert)" },
170 { PFRES_MAXSTATES, "12(state-limit)" },
171 { PFRES_SRCLIMIT, "13(src-limit)" },
172 { PFRES_SYNPROXY, "14(synproxy)" },
173 { PFRES_MAPFAILED, "15(map-failed)" },
174 { 0, NULL }
175 };
176
177 static const struct tok pf_reasons_openbsd[] = {
178 { PFRES_MATCH, "0(match)" },
179 { PFRES_BADOFF, "1(bad-offset)" },
180 { PFRES_FRAG, "2(fragment)" },
181 { PFRES_SHORT, "3(short)" },
182 { PFRES_NORM, "4(normalize)" },
183 { PFRES_MEMORY, "5(memory)" },
184 { PFRES_TS, "6(bad-timestamp)" },
185 { PFRES_CONGEST, "7(congestion)" },
186 { PFRES_IPOPTIONS, "8(ip-option)" },
187 { PFRES_PROTCKSUM, "9(proto-cksum)" },
188 { PFRES_BADSTATE, "10(state-mismatch)" },
189 { PFRES_STATEINS, "11(state-insert)" },
190 { PFRES_MAXSTATES, "12(state-limit)" },
191 { PFRES_SRCLIMIT, "13(src-limit)" },
192 { PFRES_SYNPROXY, "14(synproxy)" },
193 { PFRES_TRANSLATE, "15(translate)" },
194 { PFRES_NOROUTE, "16(no-route)" },
195 { 0, NULL }
196 };
197
198 static const struct tok pf_reasons_other[] = {
199 { PFRES_MATCH, "0(match)" },
200 { PFRES_BADOFF, "1(bad-offset)" },
201 { PFRES_FRAG, "2(fragment)" },
202 { PFRES_SHORT, "3(short)" },
203 { PFRES_NORM, "4(normalize)" },
204 { PFRES_MEMORY, "5(memory)" },
205 { PFRES_TS, "6(bad-timestamp)" },
206 { PFRES_CONGEST, "7(congestion)" },
207 { PFRES_IPOPTIONS, "8(ip-option)" },
208 { PFRES_PROTCKSUM, "9(proto-cksum)" },
209 { PFRES_BADSTATE, "10(state-mismatch)" },
210 { PFRES_STATEINS, "11(state-insert)" },
211 { PFRES_MAXSTATES, "12(state-limit)" },
212 { PFRES_SRCLIMIT, "13(src-limit)" },
213 { PFRES_SYNPROXY, "14(synproxy)" },
214 { PFRES_STATELOCKED_DUMMYNET,
215 "15(state-locked (NetBSD)/dummynet(Darwin)" },
216 { PFRES_INVPORT, "16(invalid-port (Darwin))" },
217 { 0, NULL }
218 };
219
220 /*
221 * Action values.
222 */
223 #define PFACT_PASS 0
224 #define PFACT_DROP 1
225 #define PFACT_SCRUB 2
226 #define PFACT_NOSCRUB 3
227 #define PFACT_NAT 4
228 #define PFACT_NONAT 5
229 #define PFACT_BINAT 6
230 #define PFACT_NOBINAT 7
231 #define PFACT_RDR 8
232 #define PFACT_NORDR 9
233 #define PFACT_SYNPROXY_DROP 10
234
235 /* FreeBSD and OpenBSD */
236 #define PFACT_DEFER 11
237
238 /* FreeBSD */
239 #define PFACT_MATCH 12
240
241 /* OpenBSD */
242 #define PFACT_MATCH 12
243 #define PFACT_DIVERT 13
244 #define PFACT_RT 14
245 #define PFACT_AFRT 15
246
247 /* Darwin */
248 #define PFACT_DUMMYNET 11
249 #define PFACT_NODUMMYNET 12
250 #define PFACT_NAT64 13
251 #define PFACT_NONAT64 14
252
253 static const struct tok pf_actions_freebsd[] = {
254 { PFACT_PASS, "pass" },
255 { PFACT_DROP, "block" },
256 { PFACT_SCRUB, "scrub" },
257 { PFACT_NOSCRUB, "noscrub" },
258 { PFACT_NAT, "nat" },
259 { PFACT_NONAT, "nonat" },
260 { PFACT_BINAT, "binat" },
261 { PFACT_NOBINAT, "nobinat" },
262 { PFACT_RDR, "rdr" },
263 { PFACT_NORDR, "nordr" },
264 { PFACT_SYNPROXY_DROP, "synproxy-drop" },
265 { PFACT_DEFER, "defer" },
266 { PFACT_MATCH, "match" },
267 { 0, NULL }
268 };
269
270 static const struct tok pf_actions_openbsd[] = {
271 { PFACT_PASS, "pass" },
272 { PFACT_DROP, "block" },
273 { PFACT_SCRUB, "scrub" },
274 { PFACT_NOSCRUB, "noscrub" },
275 { PFACT_NAT, "nat" },
276 { PFACT_NONAT, "nonat" },
277 { PFACT_BINAT, "binat" },
278 { PFACT_NOBINAT, "nobinat" },
279 { PFACT_RDR, "rdr" },
280 { PFACT_NORDR, "nordr" },
281 { PFACT_SYNPROXY_DROP, "synproxy-drop" },
282 { PFACT_DEFER, "defer" },
283 { PFACT_MATCH, "match" },
284 { PFACT_DIVERT, "divert" },
285 { PFACT_RT, "rt" },
286 { PFACT_AFRT, "afrt" },
287 { 0, NULL }
288 };
289
290 static const struct tok pf_actions_darwin[] = {
291 { PFACT_PASS, "pass" },
292 { PFACT_DROP, "block" },
293 { PFACT_SCRUB, "scrub" },
294 { PFACT_NOSCRUB, "noscrub" },
295 { PFACT_NAT, "nat" },
296 { PFACT_NONAT, "nonat" },
297 { PFACT_BINAT, "binat" },
298 { PFACT_NOBINAT, "nobinat" },
299 { PFACT_RDR, "rdr" },
300 { PFACT_NORDR, "nordr" },
301 { PFACT_SYNPROXY_DROP, "synproxy-drop" },
302 { PFACT_DUMMYNET, "dummynet (Darwin)" },
303 { PFACT_NODUMMYNET, "nodummynet (Darwin)" },
304 { PFACT_NAT64, "nat64 (Darwin)" },
305 { PFACT_NONAT64, "nonat64 (Darwin)" },
306 { 0, NULL }
307 };
308
309 /*
310 * Direction values.
311 */
312 #define PFDIR_INOUT 0
313 #define PFDIR_IN 1
314 #define PFDIR_OUT 2
315
316 /* OpenBSD */
317 #define PFDIR_FWD 3
318
319 static const struct tok pf_directions_freebsd[] = {
320 { PFDIR_INOUT, "in/out" },
321 { PFDIR_IN, "in" },
322 { PFDIR_OUT, "out" },
323 { 0, NULL }
324 };
325
326 static const struct tok pf_directions_openbsd[] = {
327 { PFDIR_INOUT, "in/out" },
328 { PFDIR_IN, "in" },
329 { PFDIR_OUT, "out" },
330 { PFDIR_FWD, "fwd" },
331 { 0, NULL }
332 };
333
334 static const struct tok pf_directions_other[] = {
335 { PFDIR_INOUT, "in/out" },
336 { PFDIR_IN, "in" },
337 { PFDIR_OUT, "out" },
338 { 0, NULL }
339 };
340
341 static void
342 print_pf_addr(netdissect_options *ndo, const char *tag, u_int naf,
343 const struct pf_addr *addr, const nd_uint16_t port)
344 {
345 char buf[INET6_ADDRSTRLEN];
346 uint16_t portnum;
347
348 ND_PRINT("%s ", tag);
349 ND_TCHECK_SIZE(addr);
350 switch (naf) {
351
352 case BSD_AF_INET:
353 addrtostr(addr->v4, buf, sizeof(buf));
354 break;
355
356 case BSD_AF_INET6_BSD:
357 addrtostr6(addr->v6, buf, sizeof(buf));
358 break;
359
360 default:
361 strlcpy(buf, "?", sizeof(buf));
362 break;
363 }
364 ND_PRINT("%s:", buf);
365 portnum = GET_BE_U_2(port);
366 ND_PRINT("%u", portnum);
367 }
368
369 static void
370 pflog_print(netdissect_options *ndo, const struct pfloghdr *hdr)
371 {
372 uint8_t length;
373 uint32_t rulenr, subrulenr;
374 uint32_t uid;
375 uint32_t ridentifier;
376
377 ndo->ndo_protocol = "pflog";
378 length = GET_U_1(hdr->length);
379
380 rulenr = GET_BE_U_4(hdr->rulenr);
381 subrulenr = GET_BE_U_4(hdr->subrulenr);
382 ND_PRINT("rule ");
383 if (rulenr != (uint32_t)-1) {
384 ND_PRINT("%u", rulenr);
385 if (hdr->ruleset[0] != '\0') {
386 ND_PRINT(".");
387 nd_printjnp(ndo, (const u_char*)hdr->ruleset, PFLOG_RULESET_NAME_SIZE);
388 }
389 if (subrulenr != (uint32_t)-1)
390 ND_PRINT(".%u", subrulenr);
391 }
392 ND_PRINT("/");
393
394 if (length == PFLOG_HEADER_LEN_FREEBSD)
395 ND_PRINT("%s", tok2str(pf_reasons_freebsd, "unkn(%u)", GET_U_1(hdr->reason)));
396 else if (length == PFLOG_HEADER_LEN_OPENBSD)
397 ND_PRINT("%s", tok2str(pf_reasons_openbsd, "unkn(%u)", GET_U_1(hdr->reason)));
398 else
399 ND_PRINT("%s", tok2str(pf_reasons_other, "unkn(%u)", GET_U_1(hdr->reason)));
400
401 /*
402 * In Darwin (macOS, etc.) and NetBSD, uid is set to
403 * UID_MAX if there's no UID, and UID_MAX is 2^31-1.
404 * UID_MAX is 2^31-1.
405 *
406 * In OpenBSD, uid is set to -1 if there's no UID, which
407 * means we'll see it as UINT_MAX, as we treat it as
408 * unsigned. UID_MAX is 2^32-1.
409 *
410 * In FreeBSD and DragonFly BSD, uid is set to UID_MAX
411 * if there's no UID. UID_MAX is 2^32-1.
412 *
413 * So:
414 *
415 * For OpenBSD and FreeBSD, check only for 2^32-1 (0xFFFFFFFFU)
416 * if there's no UID.
417 *
418 * For other OSes, it's either NetBSD, DragonFly BSD, or Darwin,
419 * check for both 2^31-1 (0x7FFFFFFFU) (NetBSD and Darwin) and
420 * 2^32-1 (0xFFFFFFFFU) (DragonFly BSD). That runs the risk of
421 * the UID not being printed for a DragonFly BSD log if it's
422 * 0x7FFFFFFF, but that's *probably* not going to be the case.
423 */
424 uid = GET_BE_U_4(hdr->uid);
425 if (length == PFLOG_HEADER_LEN_FREEBSD ||
426 length == PFLOG_HEADER_LEN_OPENBSD) {
427 if (uid != 0xFFFFFFFFU)
428 ND_PRINT(" [uid %u]", uid);
429 } else {
430 if (uid != 0xFFFFFFFFU && uid != 0x7FFFFFFFU)
431 ND_PRINT(" [uid %u]", uid);
432 }
433
434 if (length == PFLOG_HEADER_LEN_FREEBSD) {
435 ridentifier = GET_BE_U_4(hdr->u.freebsd.ridentifier);
436 if (ridentifier != 0)
437 ND_PRINT(" [ridentifier %u]", ridentifier);
438 }
439
440 if (length == PFLOG_HEADER_LEN_FREEBSD) {
441 ND_PRINT(": %s %s on ",
442 tok2str(pf_actions_freebsd, "unkn(%u)", GET_U_1(hdr->action)),
443 tok2str(pf_directions_freebsd, "unkn(%u)", GET_U_1(hdr->dir)));
444 } else if (length == PFLOG_HEADER_LEN_OPENBSD) {
445 ND_PRINT(": %s %s on ",
446 tok2str(pf_actions_openbsd, "unkn(%u)", GET_U_1(hdr->action)),
447 tok2str(pf_directions_openbsd, "unkn(%u)", GET_U_1(hdr->dir)));
448 } else {
449 /*
450 * We use the Darwin set of actions, as it's a superset
451 * of the NetBSD/DragonFly BSD set of actions.
452 */
453 ND_PRINT(": %s %s on ",
454 tok2str(pf_actions_darwin, "unkn(%u)", GET_U_1(hdr->action)),
455 tok2str(pf_directions_other, "unkn(%u)", GET_U_1(hdr->dir)));
456 }
457 nd_printjnp(ndo, (const u_char*)hdr->ifname, PFLOG_IFNAMSIZ);
458 ND_PRINT(": ");
459 if (length == PFLOG_HEADER_LEN_OPENBSD) {
460 if (ndo->ndo_vflag && GET_U_1(hdr->u.openbsd.rewritten)) {
461 uint8_t naf;
462
463 ND_PRINT("[rewritten: ");
464 naf = GET_U_1(hdr->u.openbsd.naf);
465 print_pf_addr(ndo, "src", naf, &hdr->u.openbsd.saddr,
466 hdr->u.openbsd.sport);
467 ND_PRINT(", ");
468 print_pf_addr(ndo, "src", naf, &hdr->u.openbsd.daddr,
469 hdr->u.openbsd.dport);
470 ND_PRINT("; ");
471 }
472 }
473 }
474
475 void
476 pflog_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h,
477 const u_char *p)
478 {
479 u_int length = h->len;
480 u_int hdrlen;
481 u_int caplen = h->caplen;
482 const struct pfloghdr *hdr;
483 uint8_t af;
484
485 ndo->ndo_protocol = "pflog";
486 /* check length */
487 ND_ICHECK_U(length, <, MIN_PFLOG_HDRLEN);
488
489 hdr = (const struct pfloghdr *)p;
490 hdrlen = GET_U_1(hdr->length);
491 ND_ICHECK_U(hdrlen, <, MIN_PFLOG_HDRLEN);
492 ND_ICHECK_U(hdrlen, >, MAX_PFLOG_HDRLEN);
493 hdrlen = roundup2(hdrlen, 4);
494
495 /* print what we know */
496 ND_TCHECK_LEN(hdr, hdrlen);
497 ndo->ndo_ll_hdr_len += hdrlen;
498 if (ndo->ndo_eflag)
499 pflog_print(ndo, hdr);
500
501 /* skip to the real packet */
502 af = GET_U_1(hdr->af);
503 length -= hdrlen;
504 caplen -= hdrlen;
505 p += hdrlen;
506 switch (af) {
507
508 /*
509 * If there's a system that doesn't use the AF_INET
510 * from 4.2BSD, feel free to add its value to af.h
511 * and use it here.
512 *
513 * Hopefully, there isn't.
514 */
515 case BSD_AF_INET:
516 ip_print(ndo, p, length);
517 break;
518
519 /*
520 * Try all AF_INET6 values for all systems with pflog,
521 * including Darwin.
522 */
523 case BSD_AF_INET6_BSD:
524 case BSD_AF_INET6_FREEBSD:
525 case BSD_AF_INET6_DARWIN:
526 ip6_print(ndo, p, length);
527 break;
528
529 default:
530 /* address family not handled, print raw packet */
531 if (!ndo->ndo_eflag)
532 pflog_print(ndo, hdr);
533 if (!ndo->ndo_suppress_default_print)
534 ND_DEFAULTPRINT(p, caplen);
535 }
536
537 return;
538
539 invalid:
540 nd_print_invalid(ndo);
541 }