]> The Tcpdump Group git mirrors - tcpdump/blob - print-pflog.c
pflog: note why we can't handle this all at run time. [skip ci]
[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
35 /*
36 * pflog headers, at least as they exist now.
37 */
38 #define PFLOG_IFNAMSIZ 16
39 #define PFLOG_RULESET_NAME_SIZE 16
40
41 struct pf_addr {
42 union {
43 nd_ipv4 v4;
44 nd_ipv6 v6;
45 } pfa; /* 128-bit address */
46 #define v4 pfa.v4
47 #define v6 pfa.v6
48 };
49
50 /*
51 * This header is:
52 *
53 * 61 bytes long on NetBSD, DragonFly BSD. and Darwin;
54 * 84 bytes lon on OpenBSD;
55 * 72 bytes long on FreeBSD;
56 *
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.
63 *
64 * (We could, I guess, label reason value 15 as
65 * "state-locked (NetBSD)/dummynet (macOS etc.)" or something such as
66 * that.)
67 */
68 struct pfloghdr {
69 nd_uint8_t length;
70 nd_uint8_t af;
71 nd_uint8_t action;
72 nd_uint8_t reason;
73 char ifname[PFLOG_IFNAMSIZ];
74 char ruleset[PFLOG_RULESET_NAME_SIZE];
75 nd_uint32_t rulenr;
76 nd_uint32_t subrulenr;
77 nd_uint32_t uid;
78 nd_int32_t pid;
79 nd_uint32_t rule_uid;
80 nd_int32_t rule_pid;
81 nd_uint8_t dir;
82 /*
83 * This is the minimum pflog header length; it includes none of
84 * the fields added either by OpenBSD or FreeBSD, and doesn't
85 * include any padding.
86 */
87 #define MIN_PFLOG_HDRLEN 61
88 #if defined(__OpenBSD__)
89 nd_uint8_t rewritten;
90 nd_uint8_t naf;
91 nd_uint8_t pad[1];
92 #else
93 nd_uint8_t pad[3];
94 #endif
95 #if defined(__FreeBSD__)
96 nd_uint32_t ridentifier;
97 nd_uint8_t reserve;
98 nd_uint8_t pad2[3];
99 #elif defined(__OpenBSD__)
100 struct pf_addr saddr;
101 struct pf_addr daddr;
102 nd_uint16_t sport;
103 nd_uint16_t dport;
104 #endif
105 };
106 #define MAX_PFLOG_HDRLEN 100 /* 61 + 3 + 16 + 16 + 2 + 2 */
107
108 /*
109 * Reason values.
110 */
111 #define PFRES_MATCH 0
112 #define PFRES_BADOFF 1
113 #define PFRES_FRAG 2
114 #define PFRES_SHORT 3
115 #define PFRES_NORM 4
116 #define PFRES_MEMORY 5
117 #define PFRES_TS 6
118 #define PFRES_CONGEST 7
119 #define PFRES_IPOPTIONS 8
120 #define PFRES_PROTCKSUM 9
121 #define PFRES_BADSTATE 10
122 #define PFRES_STATEINS 11
123 #define PFRES_MAXSTATES 12
124 #define PFRES_SRCLIMIT 13
125 #define PFRES_SYNPROXY 14
126 #if defined(__FreeBSD__)
127 #define PFRES_MAPFAILED 15
128 #elif defined(__NetBSD__)
129 #define PFRES_STATELOCKED 15
130 #elif defined(__OpenBSD__)
131 #define PFRES_TRANSLATE 15
132 #define PFRES_NOROUTE 16
133 #elif defined(__APPLE__)
134 #define PFRES_DUMMYNET 15
135 #endif
136
137 static const struct tok pf_reasons[] = {
138 { PFRES_MATCH, "0(match)" },
139 { PFRES_BADOFF, "1(bad-offset)" },
140 { PFRES_FRAG, "2(fragment)" },
141 { PFRES_SHORT, "3(short)" },
142 { PFRES_NORM, "4(normalize)" },
143 { PFRES_MEMORY, "5(memory)" },
144 { PFRES_TS, "6(bad-timestamp)" },
145 { PFRES_CONGEST, "7(congestion)" },
146 { PFRES_IPOPTIONS, "8(ip-option)" },
147 { PFRES_PROTCKSUM, "9(proto-cksum)" },
148 { PFRES_BADSTATE, "10(state-mismatch)" },
149 { PFRES_STATEINS, "11(state-insert)" },
150 { PFRES_MAXSTATES, "12(state-limit)" },
151 { PFRES_SRCLIMIT, "13(src-limit)" },
152 { PFRES_SYNPROXY, "14(synproxy)" },
153 #if defined(__FreeBSD__)
154 { PFRES_MAPFAILED, "15(map-failed)" },
155 #elif defined(__NetBSD__)
156 { PFRES_STATELOCKED, "15(state-locked)" },
157 #elif defined(__OpenBSD__)
158 { PFRES_TRANSLATE, "15(translate)" },
159 { PFRES_NOROUTE, "16(no-route)" },
160 #elif defined(__APPLE__)
161 { PFRES_DUMMYNET, "15(dummynet)" },
162 #endif
163 { 0, NULL }
164 };
165
166 /*
167 * Action values.
168 */
169 #define PF_PASS 0
170 #define PF_DROP 1
171 #define PF_SCRUB 2
172 #define PF_NOSCRUB 3
173 #define PF_NAT 4
174 #define PF_NONAT 5
175 #define PF_BINAT 6
176 #define PF_NOBINAT 7
177 #define PF_RDR 8
178 #define PF_NORDR 9
179 #define PF_SYNPROXY_DROP 10
180 #if defined(__FreeBSD__)
181 #define PF_DEFER 11
182 #define PF_MATCH 12
183 #elif defined(__OpenBSD__)
184 #define PF_DEFER 11
185 #define PF_MATCH 12
186 #define PF_DIVERT 13
187 #define PF_RT 14
188 #define PF_AFRT 15
189 #elif defined(__APPLE__)
190 #define PF_DUMMYNET 11
191 #define PF_NODUMMYNET 12
192 #define PF_NAT64 13
193 #define PF_NONAT64 14
194 #endif
195
196 static const struct tok pf_actions[] = {
197 { PF_PASS, "pass" },
198 { PF_DROP, "block" },
199 { PF_SCRUB, "scrub" },
200 { PF_NOSCRUB, "noscrub" },
201 { PF_NAT, "nat" },
202 { PF_NONAT, "nonat" },
203 { PF_BINAT, "binat" },
204 { PF_NOBINAT, "nobinat" },
205 { PF_RDR, "rdr" },
206 { PF_NORDR, "nordr" },
207 { PF_SYNPROXY_DROP, "synproxy-drop" },
208 #if defined(__FreeBSD__)
209 { PF_DEFER, "defer" },
210 { PF_MATCH, "match" },
211 #elif defined(__OpenBSD__)
212 { PF_DEFER, "defer" },
213 { PF_MATCH, "match" },
214 { PF_DIVERT, "divert" },
215 { PF_RT, "rt" },
216 { PF_AFRT, "afrt" },
217 #elif defined(__APPLE__)
218 { PF_DUMMYNET, "dummynet" },
219 { PF_NODUMMYNET, "nodummynet" },
220 { PF_NAT64, "nat64" },
221 { PF_NONAT64, "nonat64" },
222 #endif
223 { 0, NULL }
224 };
225
226 /*
227 * Direction values.
228 */
229 #define PF_INOUT 0
230 #define PF_IN 1
231 #define PF_OUT 2
232 #if defined(__OpenBSD__)
233 #define PF_FWD 3
234 #endif
235
236 static const struct tok pf_directions[] = {
237 { PF_INOUT, "in/out" },
238 { PF_IN, "in" },
239 { PF_OUT, "out" },
240 #if defined(__OpenBSD__)
241 { PF_FWD, "fwd" },
242 #endif
243 { 0, NULL }
244 };
245
246 static void
247 pflog_print(netdissect_options *ndo, const struct pfloghdr *hdr)
248 {
249 uint32_t rulenr, subrulenr;
250 #if defined(__FreeBSD__)
251 uint32_t ridentifier;
252 #endif
253
254 ndo->ndo_protocol = "pflog";
255 rulenr = GET_BE_U_4(hdr->rulenr);
256 subrulenr = GET_BE_U_4(hdr->subrulenr);
257 #if defined(__FreeBSD__)
258 ridentifier = GET_BE_U_4(hdr->ridentifier);
259 #endif
260 if (subrulenr == (uint32_t)-1)
261 ND_PRINT("rule %u/", rulenr);
262 else {
263 ND_PRINT("rule %u.", rulenr);
264 nd_printjnp(ndo, (const u_char*)hdr->ruleset, PFLOG_RULESET_NAME_SIZE);
265 ND_PRINT(".%u/", subrulenr);
266 }
267
268 ND_PRINT("%s", tok2str(pf_reasons, "unkn(%u)", GET_U_1(hdr->reason)));
269
270 /*
271 * All bits set means that the UID shouldn't be printed.
272 * That's UINT_MAX if signed, or -1 if unsigned.
273 */
274 if (GET_BE_U_4(hdr->uid) != UINT_MAX)
275 ND_PRINT(" [uid %u]", GET_BE_U_4(hdr->uid));
276
277 #if defined(__FreeBSD__)
278 if (ridentifier != 0)
279 ND_PRINT(" [ridentifier %u]", ridentifier);
280 #endif
281
282 ND_PRINT(": %s %s on ",
283 tok2str(pf_actions, "unkn(%u)", GET_U_1(hdr->action)),
284 tok2str(pf_directions, "unkn(%u)", GET_U_1(hdr->dir)));
285 nd_printjnp(ndo, (const u_char*)hdr->ifname, PFLOG_IFNAMSIZ);
286 ND_PRINT(": ");
287 }
288
289 void
290 pflog_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h,
291 const u_char *p)
292 {
293 u_int length = h->len;
294 u_int hdrlen;
295 u_int caplen = h->caplen;
296 const struct pfloghdr *hdr;
297 uint8_t af;
298
299 ndo->ndo_protocol = "pflog";
300 /* check length */
301 ND_ICHECK_U(length, <, MIN_PFLOG_HDRLEN);
302
303 hdr = (const struct pfloghdr *)p;
304 hdrlen = GET_U_1(hdr->length);
305 ND_ICHECK_U(hdrlen, <, MIN_PFLOG_HDRLEN);
306 hdrlen = roundup2(hdrlen, 4);
307 ND_ICHECK_U(hdrlen, >, MAX_PFLOG_HDRLEN);
308
309 /* print what we know */
310 ND_TCHECK_LEN(hdr, hdrlen);
311 ndo->ndo_ll_hdr_len += hdrlen;
312 if (ndo->ndo_eflag)
313 pflog_print(ndo, hdr);
314
315 /* skip to the real packet */
316 af = GET_U_1(hdr->af);
317 length -= hdrlen;
318 caplen -= hdrlen;
319 p += hdrlen;
320 switch (af) {
321
322 /*
323 * If there's a system that doesn't use the AF_INET
324 * from 4.2BSD, feel free to add its value to af.h
325 * and use it here.
326 *
327 * Hopefully, there isn't.
328 */
329 case BSD_AF_INET:
330 ip_print(ndo, p, length);
331 break;
332
333 /*
334 * Try all AF_INET6 values for all systems with pflog,
335 * including Darwin.
336 */
337 case BSD_AF_INET6_BSD:
338 case BSD_AF_INET6_FREEBSD:
339 case BSD_AF_INET6_DARWIN:
340 ip6_print(ndo, p, length);
341 break;
342
343 default:
344 /* address family not handled, print raw packet */
345 if (!ndo->ndo_eflag)
346 pflog_print(ndo, hdr);
347 if (!ndo->ndo_suppress_default_print)
348 ND_DEFAULTPRINT(p, caplen);
349 }
350
351 return;
352
353 invalid:
354 nd_print_invalid(ndo);
355 }