2 * Routines for pflog (OpenBSD Firewall Logging) packet disassembly
4 * $Id: packet-pflog.c,v 1.9 2003/05/16 00:30:54 guy Exp $
6 * Copyright 2001 Mike Frantzen
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * - Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
37 #include <epan/packet.h>
39 #include <epan/resolv.h>
40 #include "packet-ip.h"
41 #include "packet-ipv6.h"
42 #include "packet-pflog.h"
45 /* Can't trust stddef.h to be there for us */
46 # define offsetof(type, member) ((size_t)(&((type *)0)->member))
50 #define BPF_ALIGNMENT sizeof(long)
51 #define BPF_WORDALIGN(x) (((x) + (BPF_ALIGNMENT - 1)) & ~(BPF_ALIGNMENT - 1))
54 static dissector_handle_t data_handle, ip_handle, ipv6_handle;
57 static int proto_pflog = -1;
58 static int hf_pflog_length = -1;
59 static int hf_pflog_af = -1;
60 static int hf_pflog_action = -1;
61 static int hf_pflog_reason = -1;
62 static int hf_pflog_ifname = -1;
63 static int hf_pflog_ruleset = -1;
64 static int hf_pflog_rulenr = -1;
65 static int hf_pflog_subrulenr = -1;
66 static int hf_pflog_dir = -1;
68 static gint ett_pflog = -1;
71 static int proto_old_pflog = -1;
72 static int hf_old_pflog_af = -1;
73 static int hf_old_pflog_ifname = -1;
74 static int hf_old_pflog_rnr = -1;
75 static int hf_old_pflog_reason = -1;
76 static int hf_old_pflog_action = -1;
77 static int hf_old_pflog_dir = -1;
79 static gint ett_old_pflog = -1;
82 capture_pflog(const guchar *pd, int offset, int len, packet_counts *ld)
84 struct pfloghdr *pflogh;
87 pflogh = (struct pfloghdr *)pd;
89 if (!BYTES_ARE_IN_FRAME(offset, len, sizeof(guint8))) {
94 if (pflogh->length < MIN_PFLOG_HDRLEN) {
98 hdrlen = BPF_WORDALIGN(pflogh->length);
99 if (!BYTES_ARE_IN_FRAME(offset, hdrlen, sizeof(guint8))) {
105 switch (pflogh->af) {
108 capture_ip(pd, offset, len, ld);
113 capture_ipv6(pd, offset, len, ld);
123 static const value_string af_vals[] = {
124 { BSD_PF_INET, "IPv4" },
125 { BSD_PF_INET6, "IPv6" },
129 static const value_string reason_vals[] = {
139 static const value_string action_vals[] = {
140 { PF_PASS, "passed" },
141 { PF_DROP, "dropped" },
142 { PF_SCRUB, "scrubbed" },
146 static const value_string old_dir_vals[] = {
148 { PF_OLD_OUT, "out" },
152 static const value_string dir_vals[] = {
153 { PF_INOUT, "inout" },
160 dissect_pflog(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
162 #define MAX_RULE_STR 128
163 struct pfloghdr pflogh;
164 static char rulestr[MAX_RULE_STR];
166 proto_tree *pflog_tree;
170 if (check_col(pinfo->cinfo, COL_PROTOCOL))
171 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PFLOG");
173 /* Copy out the pflog header to insure alignment */
174 tvb_memcpy(tvb, (guint8 *)&pflogh, 0, sizeof(pflogh));
176 /* Byteswap the header now */
177 pflogh.rulenr = g_ntohl(pflogh.rulenr);
178 pflogh.subrulenr = g_ntohl(pflogh.subrulenr);
180 hdrlen = BPF_WORDALIGN(pflogh.length);
182 if (pflogh.subrulenr == (guint32) -1)
183 snprintf(rulestr, sizeof(rulestr), "%u",
186 snprintf(rulestr, sizeof(rulestr), "%u.%s.%u",
187 pflogh.rulenr, pflogh.ruleset, pflogh.subrulenr);
189 if (hdrlen < MIN_PFLOG_HDRLEN) {
191 ti = proto_tree_add_protocol_format(tree, proto_pflog, tvb, 0,
192 hdrlen, "PF Log invalid header length (%u)", hdrlen);
194 if (check_col(pinfo->cinfo, COL_INFO)) {
195 col_prepend_fstr(pinfo->cinfo, COL_INFO, "Invalid header length %u",
202 ti = proto_tree_add_protocol_format(tree, proto_pflog, tvb, 0,
204 "PF Log %s %s on %s by rule %s",
205 val_to_str(pflogh.af, af_vals, "unknown (%u)"),
206 val_to_str(pflogh.action, action_vals, "unknown (%u)"),
209 pflog_tree = proto_item_add_subtree(ti, ett_pflog);
211 proto_tree_add_uint(pflog_tree, hf_pflog_length, tvb,
212 offsetof(struct pfloghdr, length), sizeof(pflogh.length),
214 proto_tree_add_uint(pflog_tree, hf_pflog_af, tvb,
215 offsetof(struct pfloghdr, af), sizeof(pflogh.af),
217 proto_tree_add_uint(pflog_tree, hf_pflog_action, tvb,
218 offsetof(struct pfloghdr, action), sizeof(pflogh.action),
220 proto_tree_add_uint(pflog_tree, hf_pflog_reason, tvb,
221 offsetof(struct pfloghdr, reason), sizeof(pflogh.reason),
223 proto_tree_add_string(pflog_tree, hf_pflog_ifname, tvb,
224 offsetof(struct pfloghdr, ifname), sizeof(pflogh.ifname),
226 proto_tree_add_string(pflog_tree, hf_pflog_ruleset, tvb,
227 offsetof(struct pfloghdr, ruleset), sizeof(pflogh.ruleset),
229 proto_tree_add_int(pflog_tree, hf_pflog_rulenr, tvb,
230 offsetof(struct pfloghdr, rulenr), sizeof(pflogh.rulenr),
232 proto_tree_add_int(pflog_tree, hf_pflog_subrulenr, tvb,
233 offsetof(struct pfloghdr, subrulenr), sizeof(pflogh.subrulenr),
235 proto_tree_add_uint(pflog_tree, hf_pflog_dir, tvb,
236 offsetof(struct pfloghdr, dir), sizeof(pflogh.dir),
240 /* Set the tvbuff for the payload after the header */
241 next_tvb = tvb_new_subset(tvb, hdrlen, -1, -1);
246 call_dissector(ip_handle, next_tvb, pinfo, tree);
250 call_dissector(ipv6_handle, next_tvb, pinfo, tree);
254 call_dissector(data_handle, next_tvb, pinfo, tree);
258 if (check_col(pinfo->cinfo, COL_INFO)) {
259 col_prepend_fstr(pinfo->cinfo, COL_INFO, "[%s %s/%s] ",
260 val_to_str(pflogh.action, action_vals, "unknown (%u)"),
267 proto_register_pflog(void)
269 static hf_register_info hf[] = {
271 { "Header Length", "pflog.length", FT_UINT8, BASE_DEC, NULL, 0x0,
272 "Length of Header", HFILL }},
274 { "Address Family", "pflog.af", FT_UINT32, BASE_DEC, VALS(af_vals), 0x0,
275 "Protocol (IPv4 vs IPv6)", HFILL }},
277 { "Action", "pflog.action", FT_UINT8, BASE_DEC, VALS(action_vals), 0x0,
278 "Action taken by PF on the packet", HFILL }},
280 { "Reason", "pflog.reason", FT_UINT8, BASE_DEC, VALS(reason_vals), 0x0,
281 "Reason for logging the packet", HFILL }},
283 { "Interface", "pflog.ifname", FT_STRING, BASE_NONE, NULL, 0x0,
284 "Interface", HFILL }},
286 { "Ruleset", "pflog.ruleset", FT_STRING, BASE_NONE, NULL, 0x0,
287 "Ruleset name in anchor", HFILL }},
289 { "Rule Number", "pflog.rulenr", FT_INT32, BASE_DEC, NULL, 0x0,
290 "Last matched firewall main ruleset rule number", HFILL }},
291 { &hf_pflog_subrulenr,
292 { "Sub Rule Number", "pflog.subrulenr", FT_INT32, BASE_DEC, NULL, 0x0,
293 "Last matched firewall anchored ruleset rule number", HFILL }},
295 { "Direction", "pflog.dir", FT_UINT8, BASE_DEC, VALS(dir_vals), 0x0,
296 "Direction of packet in stack (inbound versus outbound)", HFILL }},
298 static gint *ett[] = { &ett_pflog };
300 proto_pflog = proto_register_protocol("OpenBSD Packet Filter log file",
302 proto_register_field_array(proto_pflog, hf, array_length(hf));
303 proto_register_subtree_array(ett, array_length(ett));
307 proto_reg_handoff_pflog(void)
309 dissector_handle_t pflog_handle;
311 ip_handle = find_dissector("ip");
312 ipv6_handle = find_dissector("ipv6");
313 data_handle = find_dissector("data");
315 pflog_handle = create_dissector_handle(dissect_pflog, proto_pflog);
316 dissector_add("wtap_encap", WTAP_ENCAP_PFLOG, pflog_handle);
321 capture_old_pflog(const guchar *pd, int offset, int len, packet_counts *ld)
323 struct old_pfloghdr pflogh;
325 if (!BYTES_ARE_IN_FRAME(offset, len, (int)OLD_PFLOG_HDRLEN)) {
330 offset += OLD_PFLOG_HDRLEN;
332 /* Copy out the pflog header to insure alignment */
333 memcpy(&pflogh, pd, sizeof(pflogh));
334 pflogh.af = g_ntohl(pflogh.af);
339 capture_ip(pd, offset, len, ld);
344 capture_ipv6(pd, offset, len, ld);
355 dissect_old_pflog(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
357 struct old_pfloghdr pflogh;
359 proto_tree *pflog_tree;
362 if (check_col(pinfo->cinfo, COL_PROTOCOL))
363 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PFLOG-OLD");
365 /* Copy out the pflog header to insure alignment */
366 tvb_memcpy(tvb, (guint8 *)&pflogh, 0, sizeof(pflogh));
368 /* Byteswap the header now */
369 pflogh.af = g_ntohl(pflogh.af);
370 pflogh.rnr = g_ntohs(pflogh.rnr);
371 pflogh.reason = g_ntohs(pflogh.reason);
372 pflogh.action = g_ntohs(pflogh.action);
373 pflogh.dir = g_ntohs(pflogh.dir);
376 ti = proto_tree_add_protocol_format(tree, proto_old_pflog, tvb, 0,
378 "PF Log (pre 3.4) %s %s on %s by rule %d",
379 val_to_str(pflogh.af, af_vals, "unknown (%u)"),
380 val_to_str(pflogh.action, action_vals, "unknown (%u)"),
383 pflog_tree = proto_item_add_subtree(ti, ett_pflog);
385 proto_tree_add_uint(pflog_tree, hf_old_pflog_af, tvb,
386 offsetof(struct old_pfloghdr, af), sizeof(pflogh.af),
388 proto_tree_add_int(pflog_tree, hf_old_pflog_rnr, tvb,
389 offsetof(struct old_pfloghdr, rnr), sizeof(pflogh.rnr),
391 proto_tree_add_string(pflog_tree, hf_old_pflog_ifname, tvb,
392 offsetof(struct old_pfloghdr, ifname), sizeof(pflogh.ifname),
394 proto_tree_add_uint(pflog_tree, hf_old_pflog_reason, tvb,
395 offsetof(struct old_pfloghdr, reason), sizeof(pflogh.reason),
397 proto_tree_add_uint(pflog_tree, hf_old_pflog_action, tvb,
398 offsetof(struct old_pfloghdr, action), sizeof(pflogh.action),
400 proto_tree_add_uint(pflog_tree, hf_old_pflog_dir, tvb,
401 offsetof(struct old_pfloghdr, dir), sizeof(pflogh.dir),
405 /* Set the tvbuff for the payload after the header */
406 next_tvb = tvb_new_subset(tvb, OLD_PFLOG_HDRLEN, -1, -1);
411 call_dissector(ip_handle, next_tvb, pinfo, tree);
415 call_dissector(ipv6_handle, next_tvb, pinfo, tree);
419 call_dissector(data_handle, next_tvb, pinfo, tree);
423 if (check_col(pinfo->cinfo, COL_INFO)) {
424 col_prepend_fstr(pinfo->cinfo, COL_INFO, "[%s %s/#%d] ",
425 val_to_str(pflogh.action, action_vals, "unknown (%u)"),
432 proto_register_old_pflog(void)
434 static hf_register_info hf[] = {
436 { "Address Family", "pflog.af", FT_UINT32, BASE_DEC, VALS(af_vals), 0x0,
437 "Protocol (IPv4 vs IPv6)", HFILL }},
438 { &hf_old_pflog_ifname,
439 { "Interface", "pflog.ifname", FT_STRING, BASE_NONE, NULL, 0x0,
440 "Interface", HFILL }},
442 { "Rule Number", "pflog.rnr", FT_INT16, BASE_DEC, NULL, 0x0,
443 "Last matched firewall rule number", HFILL }},
444 { &hf_old_pflog_reason,
445 { "Reason", "pflog.reason", FT_UINT16, BASE_DEC, VALS(reason_vals), 0x0,
446 "Reason for logging the packet", HFILL }},
447 { &hf_old_pflog_action,
448 { "Action", "pflog.action", FT_UINT16, BASE_DEC, VALS(action_vals), 0x0,
449 "Action taken by PF on the packet", HFILL }},
451 { "Direction", "pflog.dir", FT_UINT16, BASE_DEC, VALS(old_dir_vals), 0x0,
452 "Direction of packet in stack (inbound versus outbound)", HFILL }},
454 static gint *ett[] = { &ett_old_pflog };
456 proto_old_pflog = proto_register_protocol(
457 "OpenBSD Packet Filter log file, pre 3.4",
458 "PFLOG-OLD", "pflog-old");
459 proto_register_field_array(proto_old_pflog, hf, array_length(hf));
460 proto_register_subtree_array(ett, array_length(ett));
464 proto_reg_handoff_old_pflog(void)
466 dissector_handle_t pflog_handle;
468 ip_handle = find_dissector("ip");
469 ipv6_handle = find_dissector("ipv6");
470 data_handle = find_dissector("data");
472 pflog_handle = create_dissector_handle(dissect_old_pflog, proto_old_pflog);
473 dissector_add("wtap_encap", WTAP_ENCAP_OLD_PFLOG, pflog_handle);