2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996
3 * The Regents of the University of California. All rights reserved.
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
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.
22 /* \summary: *BSD/Darwin packet filter log file printer */
28 #include "netdissect-stdinc.h"
30 #define ND_LONGJMP_FROM_TCHECK
31 #include "netdissect.h"
36 * pflog headers, at least as they exist now.
38 #define PFLOG_IFNAMSIZ 16
39 #define PFLOG_RULESET_NAME_SIZE 16
45 } pfa
; /* 128-bit address */
53 * 61 bytes long on NetBSD, DragonFly BSD. and Darwin;
54 * 84 bytes lon on OpenBSD;
55 * 72 bytes long on FreeBSD;
57 * which, unfortunately, does not allow us to distinguish, based on
58 * the header length, between the three OSes listed as having 61-byte
59 * headers. As the action values differ between them, this makes it
60 * impossible to correctly dissect the reason values that differ
61 * between NetBSD and Darwin (reason value 15) without having some
62 * way to explicitly tell tcpdump what to do.
64 * (We could, I guess, label reason value 15 as
65 * "state-locked (NetBSD)/dummynet (macOS etc.)" or something such as
73 char ifname
[PFLOG_IFNAMSIZ
];
74 char ruleset
[PFLOG_RULESET_NAME_SIZE
];
76 nd_uint32_t subrulenr
;
83 struct pflog_openbsd_only
{
92 struct pflog_freebsd_only
{
94 nd_uint32_t ridentifier
;
101 * FreeBSD header length.
103 #define PFLOG_HEADER_LEN_FREEBSD 69
106 * OpenBSD header length.
108 #define PFLOG_HEADER_LEN_OPENBSD 100
111 * DragonFly BSD, NetBSD and Darwin header length.
112 * Older versions of FreeBSD and OpenBSD may have used this
115 * Unfortunately, this means we can't distinguish between Darwin, NetBSD,
116 * and DragonFly BSD based on the header length.
118 #define PFLOG_HEADER_LEN_OTHER 61
121 * These are the minimum and maximum pflog header lengths.
123 #define MIN_PFLOG_HDRLEN 61
124 #define MAX_PFLOG_HDRLEN 100
129 #define PFRES_MATCH 0
130 #define PFRES_BADOFF 1
132 #define PFRES_SHORT 3
134 #define PFRES_MEMORY 5
136 #define PFRES_CONGEST 7
137 #define PFRES_IPOPTIONS 8
138 #define PFRES_PROTCKSUM 9
139 #define PFRES_BADSTATE 10
140 #define PFRES_STATEINS 11
141 #define PFRES_MAXSTATES 12
142 #define PFRES_SRCLIMIT 13
143 #define PFRES_SYNPROXY 14
146 #define PFRES_MAPFAILED 15
149 #define PFRES_TRANSLATE 15
150 #define PFRES_NOROUTE 16
153 #define PFRES_STATELOCKED_DUMMYNET 15 /* STATELOCKED on NetBSD, DUMMYNET on Darwin */
154 #define PFRES_INVPORT 16 /* INVPORT on Darwin */
156 static const struct tok pf_reasons_freebsd
[] = {
157 { PFRES_MATCH
, "0(match)" },
158 { PFRES_BADOFF
, "1(bad-offset)" },
159 { PFRES_FRAG
, "2(fragment)" },
160 { PFRES_SHORT
, "3(short)" },
161 { PFRES_NORM
, "4(normalize)" },
162 { PFRES_MEMORY
, "5(memory)" },
163 { PFRES_TS
, "6(bad-timestamp)" },
164 { PFRES_CONGEST
, "7(congestion)" },
165 { PFRES_IPOPTIONS
, "8(ip-option)" },
166 { PFRES_PROTCKSUM
, "9(proto-cksum)" },
167 { PFRES_BADSTATE
, "10(state-mismatch)" },
168 { PFRES_STATEINS
, "11(state-insert)" },
169 { PFRES_MAXSTATES
, "12(state-limit)" },
170 { PFRES_SRCLIMIT
, "13(src-limit)" },
171 { PFRES_SYNPROXY
, "14(synproxy)" },
172 { PFRES_MAPFAILED
, "15(map-failed)" },
176 static const struct tok pf_reasons_openbsd
[] = {
177 { PFRES_MATCH
, "0(match)" },
178 { PFRES_BADOFF
, "1(bad-offset)" },
179 { PFRES_FRAG
, "2(fragment)" },
180 { PFRES_SHORT
, "3(short)" },
181 { PFRES_NORM
, "4(normalize)" },
182 { PFRES_MEMORY
, "5(memory)" },
183 { PFRES_TS
, "6(bad-timestamp)" },
184 { PFRES_CONGEST
, "7(congestion)" },
185 { PFRES_IPOPTIONS
, "8(ip-option)" },
186 { PFRES_PROTCKSUM
, "9(proto-cksum)" },
187 { PFRES_BADSTATE
, "10(state-mismatch)" },
188 { PFRES_STATEINS
, "11(state-insert)" },
189 { PFRES_MAXSTATES
, "12(state-limit)" },
190 { PFRES_SRCLIMIT
, "13(src-limit)" },
191 { PFRES_SYNPROXY
, "14(synproxy)" },
192 { PFRES_TRANSLATE
, "15(translate)" },
193 { PFRES_NOROUTE
, "16(no-route)" },
197 static const struct tok pf_reasons_other
[] = {
198 { PFRES_MATCH
, "0(match)" },
199 { PFRES_BADOFF
, "1(bad-offset)" },
200 { PFRES_FRAG
, "2(fragment)" },
201 { PFRES_SHORT
, "3(short)" },
202 { PFRES_NORM
, "4(normalize)" },
203 { PFRES_MEMORY
, "5(memory)" },
204 { PFRES_TS
, "6(bad-timestamp)" },
205 { PFRES_CONGEST
, "7(congestion)" },
206 { PFRES_IPOPTIONS
, "8(ip-option)" },
207 { PFRES_PROTCKSUM
, "9(proto-cksum)" },
208 { PFRES_BADSTATE
, "10(state-mismatch)" },
209 { PFRES_STATEINS
, "11(state-insert)" },
210 { PFRES_MAXSTATES
, "12(state-limit)" },
211 { PFRES_SRCLIMIT
, "13(src-limit)" },
212 { PFRES_SYNPROXY
, "14(synproxy)" },
213 { PFRES_STATELOCKED_DUMMYNET
,
214 "15(state-locked (NetBSD)/dummynet(Darwin)" },
215 { PFRES_INVPORT
, "16(invalid-port (Darwin))" },
224 #define PFACT_SCRUB 2
225 #define PFACT_NOSCRUB 3
227 #define PFACT_NONAT 5
228 #define PFACT_BINAT 6
229 #define PFACT_NOBINAT 7
231 #define PFACT_NORDR 9
232 #define PFACT_SYNPROXY_DROP 10
234 /* FreeBSD and OpenBSD */
235 #define PFACT_DEFER 11
238 #define PFACT_MATCH 12
241 #define PFACT_MATCH 12
242 #define PFACT_DIVERT 13
244 #define PFACT_AFRT 15
247 #define PFACT_DUMMYNET 11
248 #define PFACT_NODUMMYNET 12
249 #define PFACT_NAT64 13
250 #define PFACT_NONAT64 14
252 static const struct tok pf_actions_freebsd
[] = {
253 { PFACT_PASS
, "pass" },
254 { PFACT_DROP
, "block" },
255 { PFACT_SCRUB
, "scrub" },
256 { PFACT_NOSCRUB
, "noscrub" },
257 { PFACT_NAT
, "nat" },
258 { PFACT_NONAT
, "nonat" },
259 { PFACT_BINAT
, "binat" },
260 { PFACT_NOBINAT
, "nobinat" },
261 { PFACT_RDR
, "rdr" },
262 { PFACT_NORDR
, "nordr" },
263 { PFACT_SYNPROXY_DROP
, "synproxy-drop" },
264 { PFACT_DEFER
, "defer" },
265 { PFACT_MATCH
, "match" },
269 static const struct tok pf_actions_openbsd
[] = {
270 { PFACT_PASS
, "pass" },
271 { PFACT_DROP
, "block" },
272 { PFACT_SCRUB
, "scrub" },
273 { PFACT_NOSCRUB
, "noscrub" },
274 { PFACT_NAT
, "nat" },
275 { PFACT_NONAT
, "nonat" },
276 { PFACT_BINAT
, "binat" },
277 { PFACT_NOBINAT
, "nobinat" },
278 { PFACT_RDR
, "rdr" },
279 { PFACT_NORDR
, "nordr" },
280 { PFACT_SYNPROXY_DROP
, "synproxy-drop" },
281 { PFACT_DEFER
, "defer" },
282 { PFACT_MATCH
, "match" },
283 { PFACT_DIVERT
, "divert" },
285 { PFACT_AFRT
, "afrt" },
289 static const struct tok pf_actions_darwin
[] = {
290 { PFACT_PASS
, "pass" },
291 { PFACT_DROP
, "block" },
292 { PFACT_SCRUB
, "scrub" },
293 { PFACT_NOSCRUB
, "noscrub" },
294 { PFACT_NAT
, "nat" },
295 { PFACT_NONAT
, "nonat" },
296 { PFACT_BINAT
, "binat" },
297 { PFACT_NOBINAT
, "nobinat" },
298 { PFACT_RDR
, "rdr" },
299 { PFACT_NORDR
, "nordr" },
300 { PFACT_SYNPROXY_DROP
, "synproxy-drop" },
301 { PFACT_DUMMYNET
, "dummynet (Darwin)" },
302 { PFACT_NODUMMYNET
, "nodummynet (Darwin)" },
303 { PFACT_NAT64
, "nat64 (Darwin)" },
304 { PFACT_NONAT64
, "nonat64 (Darwin)" },
311 #define PFDIR_INOUT 0
318 static const struct tok pf_directions_freebsd
[] = {
319 { PFDIR_INOUT
, "in/out" },
321 { PFDIR_OUT
, "out" },
325 static const struct tok pf_directions_openbsd
[] = {
326 { PFDIR_INOUT
, "in/out" },
328 { PFDIR_OUT
, "out" },
329 { PFDIR_FWD
, "fwd" },
333 static const struct tok pf_directions_other
[] = {
334 { PFDIR_INOUT
, "in/out" },
336 { PFDIR_OUT
, "out" },
341 pflog_print(netdissect_options
*ndo
, const struct pfloghdr
*hdr
)
344 uint32_t rulenr
, subrulenr
;
346 uint32_t ridentifier
;
348 ndo
->ndo_protocol
= "pflog";
349 length
= GET_U_1(hdr
->length
);
351 rulenr
= GET_BE_U_4(hdr
->rulenr
);
352 subrulenr
= GET_BE_U_4(hdr
->subrulenr
);
354 if (rulenr
!= (uint32_t)-1) {
355 ND_PRINT("%u", rulenr
);
356 if (hdr
->ruleset
[0] != '\0') {
358 nd_printjnp(ndo
, (const u_char
*)hdr
->ruleset
, PFLOG_RULESET_NAME_SIZE
);
360 if (subrulenr
!= (uint32_t)-1)
361 ND_PRINT(".%u", subrulenr
);
365 if (length
== PFLOG_HEADER_LEN_FREEBSD
)
366 ND_PRINT("%s", tok2str(pf_reasons_freebsd
, "unkn(%u)", GET_U_1(hdr
->reason
)));
367 else if (length
== PFLOG_HEADER_LEN_OPENBSD
)
368 ND_PRINT("%s", tok2str(pf_reasons_openbsd
, "unkn(%u)", GET_U_1(hdr
->reason
)));
370 ND_PRINT("%s", tok2str(pf_reasons_other
, "unkn(%u)", GET_U_1(hdr
->reason
)));
373 * In Darwin (macOS, etc.) and NetBSD, uid is set to
374 * UID_MAX if there's no UID, and UID_MAX is 2^31-1.
377 * In OpenBSD, uid is set to -1 if there's no UID, which
378 * means we'll see it as UINT_MAX, as we treat it as
379 * unsigned. UID_MAX is 2^32-1.
381 * In FreeBSD and DragonFly BSD, uid is set to UID_MAX
382 * if there's no UID. UID_MAX is 2^32-1.
386 * For OpenBSD and FreeBSD, check only for 2^32-1 (0xFFFFFFFFU)
389 * For other OSes, it's either NetBSD, DragonFly BSD, or Darwin,
390 * check for both 2^31-1 (0x7FFFFFFFU) (NetBSD and Darwin) and
391 * 2^32-1 (0xFFFFFFFFU) (DragonFly BSD). That runs the risk of
392 * the UID not being printed for a DragonFly BSD log if it's
393 * 0x7FFFFFFF, but that's *probably* not going to be the case.
395 uid
= GET_BE_U_4(hdr
->uid
);
396 if (length
== PFLOG_HEADER_LEN_FREEBSD
||
397 length
== PFLOG_HEADER_LEN_OPENBSD
) {
398 if (uid
!= 0xFFFFFFFFU
)
399 ND_PRINT(" [uid %u]", uid
);
401 if (uid
!= 0xFFFFFFFFU
&& uid
!= 0x7FFFFFFFU
)
402 ND_PRINT(" [uid %u]", uid
);
405 if (length
== PFLOG_HEADER_LEN_FREEBSD
) {
406 ridentifier
= GET_BE_U_4(hdr
->u
.freebsd
.ridentifier
);
407 if (ridentifier
!= 0)
408 ND_PRINT(" [ridentifier %u]", ridentifier
);
411 if (length
== PFLOG_HEADER_LEN_FREEBSD
) {
412 ND_PRINT(": %s %s on ",
413 tok2str(pf_actions_freebsd
, "unkn(%u)", GET_U_1(hdr
->action
)),
414 tok2str(pf_directions_freebsd
, "unkn(%u)", GET_U_1(hdr
->dir
)));
415 } else if (length
== PFLOG_HEADER_LEN_OPENBSD
) {
416 ND_PRINT(": %s %s on ",
417 tok2str(pf_actions_openbsd
, "unkn(%u)", GET_U_1(hdr
->action
)),
418 tok2str(pf_directions_openbsd
, "unkn(%u)", GET_U_1(hdr
->dir
)));
421 * We use the Darwin set of actions, as it's a superset
422 * of the NetBSD/DragonFly BSD set of actions.
424 ND_PRINT(": %s %s on ",
425 tok2str(pf_actions_darwin
, "unkn(%u)", GET_U_1(hdr
->action
)),
426 tok2str(pf_directions_other
, "unkn(%u)", GET_U_1(hdr
->dir
)));
428 nd_printjnp(ndo
, (const u_char
*)hdr
->ifname
, PFLOG_IFNAMSIZ
);
433 pflog_if_print(netdissect_options
*ndo
, const struct pcap_pkthdr
*h
,
436 u_int length
= h
->len
;
438 u_int caplen
= h
->caplen
;
439 const struct pfloghdr
*hdr
;
442 ndo
->ndo_protocol
= "pflog";
444 ND_ICHECK_U(length
, <, MIN_PFLOG_HDRLEN
);
446 hdr
= (const struct pfloghdr
*)p
;
447 hdrlen
= GET_U_1(hdr
->length
);
448 ND_ICHECK_U(hdrlen
, <, MIN_PFLOG_HDRLEN
);
449 ND_ICHECK_U(hdrlen
, >, MAX_PFLOG_HDRLEN
);
450 hdrlen
= roundup2(hdrlen
, 4);
452 /* print what we know */
453 ND_TCHECK_LEN(hdr
, hdrlen
);
454 ndo
->ndo_ll_hdr_len
+= hdrlen
;
456 pflog_print(ndo
, hdr
);
458 /* skip to the real packet */
459 af
= GET_U_1(hdr
->af
);
466 * If there's a system that doesn't use the AF_INET
467 * from 4.2BSD, feel free to add its value to af.h
470 * Hopefully, there isn't.
473 ip_print(ndo
, p
, length
);
477 * Try all AF_INET6 values for all systems with pflog,
480 case BSD_AF_INET6_BSD
:
481 case BSD_AF_INET6_FREEBSD
:
482 case BSD_AF_INET6_DARWIN
:
483 ip6_print(ndo
, p
, length
);
487 /* address family not handled, print raw packet */
489 pflog_print(ndo
, hdr
);
490 if (!ndo
->ndo_suppress_default_print
)
491 ND_DEFAULTPRINT(p
, caplen
);
497 nd_print_invalid(ndo
);