+/*
+ * pflog headers, at least as they exist now.
+ */
+#define PFLOG_IFNAMSIZ 16
+#define PFLOG_RULESET_NAME_SIZE 16
+
+struct pf_addr {
+ union {
+ nd_ipv4 v4;
+ nd_ipv6 v6;
+ } pfa; /* 128-bit address */
+#define v4 pfa.v4
+#define v6 pfa.v6
+};
+
+/*
+ * This header is:
+ *
+ * 61 bytes long on NetBSD, DragonFly BSD. and Darwin;
+ * 84 bytes lon on OpenBSD;
+ * 72 bytes long on FreeBSD;
+ *
+ * which, unfortunately, does not allow us to distinguish, based on
+ * the header length, between the three OSes listed as having 61-byte
+ * headers. As the action values differ between them, this makes it
+ * impossible to correctly dissect the reason values that differ
+ * between NetBSD and Darwin (reason value 15) without having some
+ * way to explicitly tell tcpdump what to do.
+ *
+ * (We could, I guess, label reason value 15 as
+ * "state-locked (NetBSD)/dummynet (macOS etc.)" or something such as
+ * that.)
+ */
+struct pfloghdr {
+ nd_uint8_t length;
+ nd_uint8_t af;
+ nd_uint8_t action;
+ nd_uint8_t reason;
+ char ifname[PFLOG_IFNAMSIZ];
+ char ruleset[PFLOG_RULESET_NAME_SIZE];
+ nd_uint32_t rulenr;
+ nd_uint32_t subrulenr;
+ nd_uint32_t uid;
+ nd_int32_t pid;
+ nd_uint32_t rule_uid;
+ nd_int32_t rule_pid;
+ nd_uint8_t dir;
+ union {
+ struct pflog_openbsd_only {
+ nd_uint8_t rewritten;
+ nd_uint8_t naf;
+ nd_uint8_t pad[1];
+ struct pf_addr saddr;
+ struct pf_addr daddr;
+ nd_uint16_t sport;
+ nd_uint16_t dport;
+ } openbsd;
+ struct pflog_freebsd_only {
+ nd_uint8_t pad[3];
+ nd_uint32_t ridentifier;
+ nd_uint8_t reserve;
+ } freebsd;
+ } u;
+};
+
+/*
+ * FreeBSD header length.
+ */
+#define PFLOG_HEADER_LEN_FREEBSD 69
+
+/*
+ * OpenBSD header length.
+ */
+#define PFLOG_HEADER_LEN_OPENBSD 100
+
+/*
+ * DragonFly BSD, NetBSD and Darwin header length.
+ * Older versions of FreeBSD and OpenBSD may have used this
+ * as well.
+ *
+ * Unfortunately, this means we can't distinguish between Darwin, NetBSD,
+ * and DragonFly BSD based on the header length.
+ */
+#define PFLOG_HEADER_LEN_OTHER 61
+
+/*
+ * These are the minimum and maximum pflog header lengths.
+ */
+#define MIN_PFLOG_HDRLEN 61
+#define MAX_PFLOG_HDRLEN 100
+
+/*
+ * Reason values.
+ */
+#define PFRES_MATCH 0
+#define PFRES_BADOFF 1
+#define PFRES_FRAG 2
+#define PFRES_SHORT 3
+#define PFRES_NORM 4
+#define PFRES_MEMORY 5
+#define PFRES_TS 6
+#define PFRES_CONGEST 7
+#define PFRES_IPOPTIONS 8
+#define PFRES_PROTCKSUM 9
+#define PFRES_BADSTATE 10
+#define PFRES_STATEINS 11
+#define PFRES_MAXSTATES 12
+#define PFRES_SRCLIMIT 13
+#define PFRES_SYNPROXY 14
+
+/* FreeBSD */
+#define PFRES_MAPFAILED 15
+
+/* OpenBSD */
+#define PFRES_TRANSLATE 15
+#define PFRES_NOROUTE 16
+
+/* NetBSD/Darwin */
+#define PFRES_STATELOCKED_DUMMYNET 15 /* STATELOCKED on NetBSD, DUMMYNET on Darwin */
+#define PFRES_INVPORT 16 /* INVPORT on Darwin */
+
+static const struct tok pf_reasons_freebsd[] = {
+ { PFRES_MATCH, "0(match)" },
+ { PFRES_BADOFF, "1(bad-offset)" },
+ { PFRES_FRAG, "2(fragment)" },
+ { PFRES_SHORT, "3(short)" },
+ { PFRES_NORM, "4(normalize)" },
+ { PFRES_MEMORY, "5(memory)" },
+ { PFRES_TS, "6(bad-timestamp)" },
+ { PFRES_CONGEST, "7(congestion)" },
+ { PFRES_IPOPTIONS, "8(ip-option)" },
+ { PFRES_PROTCKSUM, "9(proto-cksum)" },
+ { PFRES_BADSTATE, "10(state-mismatch)" },
+ { PFRES_STATEINS, "11(state-insert)" },
+ { PFRES_MAXSTATES, "12(state-limit)" },
+ { PFRES_SRCLIMIT, "13(src-limit)" },
+ { PFRES_SYNPROXY, "14(synproxy)" },
+ { PFRES_MAPFAILED, "15(map-failed)" },
+ { 0, NULL }
+};
+
+static const struct tok pf_reasons_openbsd[] = {
+ { PFRES_MATCH, "0(match)" },
+ { PFRES_BADOFF, "1(bad-offset)" },
+ { PFRES_FRAG, "2(fragment)" },
+ { PFRES_SHORT, "3(short)" },
+ { PFRES_NORM, "4(normalize)" },
+ { PFRES_MEMORY, "5(memory)" },
+ { PFRES_TS, "6(bad-timestamp)" },
+ { PFRES_CONGEST, "7(congestion)" },
+ { PFRES_IPOPTIONS, "8(ip-option)" },
+ { PFRES_PROTCKSUM, "9(proto-cksum)" },
+ { PFRES_BADSTATE, "10(state-mismatch)" },
+ { PFRES_STATEINS, "11(state-insert)" },
+ { PFRES_MAXSTATES, "12(state-limit)" },
+ { PFRES_SRCLIMIT, "13(src-limit)" },
+ { PFRES_SYNPROXY, "14(synproxy)" },
+ { PFRES_TRANSLATE, "15(translate)" },
+ { PFRES_NOROUTE, "16(no-route)" },
+ { 0, NULL }
+};
+
+static const struct tok pf_reasons_other[] = {
+ { PFRES_MATCH, "0(match)" },
+ { PFRES_BADOFF, "1(bad-offset)" },
+ { PFRES_FRAG, "2(fragment)" },
+ { PFRES_SHORT, "3(short)" },
+ { PFRES_NORM, "4(normalize)" },
+ { PFRES_MEMORY, "5(memory)" },
+ { PFRES_TS, "6(bad-timestamp)" },
+ { PFRES_CONGEST, "7(congestion)" },
+ { PFRES_IPOPTIONS, "8(ip-option)" },
+ { PFRES_PROTCKSUM, "9(proto-cksum)" },
+ { PFRES_BADSTATE, "10(state-mismatch)" },
+ { PFRES_STATEINS, "11(state-insert)" },
+ { PFRES_MAXSTATES, "12(state-limit)" },
+ { PFRES_SRCLIMIT, "13(src-limit)" },
+ { PFRES_SYNPROXY, "14(synproxy)" },
+ { PFRES_STATELOCKED_DUMMYNET,
+ "15(state-locked (NetBSD)/dummynet(Darwin)" },
+ { PFRES_INVPORT, "16(invalid-port (Darwin))" },