As the gtk2 directory is no longer needed (GTK1 and 2 are using the same sources...
[obnox/wireshark/wip.git] / packet-pflog.c
1 /* packet-pflog.c
2  * Routines for pflog (OpenBSD Firewall Logging) packet disassembly
3  *
4  * $Id$
5  *
6  * Copyright 2001 Mike Frantzen
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  *    - Redistributions of source code must retain the above copyright
14  *      notice, this list of conditions and the following disclaimer.
15  *      with the distribution.
16  *
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.
29  */
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <string.h>
36 #include <glib.h>
37 #include <epan/packet.h>
38 #include "etypes.h"
39 #include <epan/resolv.h>
40 #include "packet-ip.h"
41 #include "packet-ipv6.h"
42 #include "packet-pflog.h"
43
44 #ifndef offsetof
45 /* Can't trust stddef.h to be there for us */
46 # define offsetof(type, member) ((size_t)(&((type *)0)->member))
47 #endif
48
49 #ifndef BPF_WORDALIGN
50 #define BPF_ALIGNMENT sizeof(long)
51 #define BPF_WORDALIGN(x) (((x) + (BPF_ALIGNMENT - 1)) & ~(BPF_ALIGNMENT - 1))
52 #endif
53
54 static dissector_handle_t  data_handle, ip_handle, ipv6_handle;
55
56 /* header fields */
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;
67
68 static gint ett_pflog = -1;
69
70 /* old header */
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;
78
79 static gint ett_old_pflog = -1;
80
81 void
82 capture_pflog(const guchar *pd, int offset, int len, packet_counts *ld)
83 {
84   struct pfloghdr *pflogh;
85   unsigned int hdrlen;
86
87   pflogh = (struct pfloghdr *)pd;
88
89   if (!BYTES_ARE_IN_FRAME(offset, len, sizeof(guint8))) {
90     ld->other++;
91     return;
92   }
93
94   if (pflogh->length < MIN_PFLOG_HDRLEN) {
95     ld->other++;
96     return;
97   }
98   hdrlen = BPF_WORDALIGN(pflogh->length);
99   if (!BYTES_ARE_IN_FRAME(offset, hdrlen, sizeof(guint8))) {
100     ld->other++;
101     return;
102   }
103   offset += hdrlen;
104
105   switch (pflogh->af) {
106
107   case BSD_PF_INET:
108     capture_ip(pd, offset, len, ld);
109     break;
110
111 #ifdef notyet
112   case BSD_PF_INET6:
113     capture_ipv6(pd, offset, len, ld);
114     break;
115 #endif
116
117   default:
118     ld->other++;
119     break;
120   }
121 }
122
123 static const value_string af_vals[] = {
124   { BSD_PF_INET,  "IPv4" },
125   { BSD_PF_INET6, "IPv6" },
126   { 0,            NULL }
127 };
128
129 static const value_string reason_vals[] = {
130   { 0, "match" },
131   { 1, "bad-offset" },
132   { 2, "fragment" },
133   { 3, "short" },
134   { 4, "normalize" },
135   { 5, "memory" },
136   { 0, NULL }
137 };
138
139 static const value_string action_vals[] = {
140   { PF_PASS,  "passed" },
141   { PF_DROP,  "dropped" },
142   { PF_SCRUB, "scrubbed" },
143   { 0,        NULL }
144 };
145
146 static const value_string old_dir_vals[] = {
147   { PF_OLD_IN,  "in" },
148   { PF_OLD_OUT, "out" },
149   { 0,          NULL }
150 };
151
152 static const value_string dir_vals[] = {
153   { PF_INOUT, "inout" },
154   { PF_IN,    "in" },
155   { PF_OUT,   "out" },
156   { 0,        NULL }
157 };
158
159 static void
160 dissect_pflog(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
161 {
162 #define MAX_RULE_STR 128
163   struct pfloghdr pflogh;
164   static char rulestr[MAX_RULE_STR];
165   tvbuff_t *next_tvb;
166   proto_tree *pflog_tree;
167   proto_item *ti;
168   int hdrlen;
169
170   if (check_col(pinfo->cinfo, COL_PROTOCOL))
171     col_set_str(pinfo->cinfo, COL_PROTOCOL, "PFLOG");
172
173   /* Copy out the pflog header to insure alignment */
174   tvb_memcpy(tvb, (guint8 *)&pflogh, 0, sizeof(pflogh));
175
176   /* Byteswap the header now */
177   pflogh.rulenr = g_ntohl(pflogh.rulenr);
178   pflogh.subrulenr = g_ntohl(pflogh.subrulenr);
179
180   hdrlen = BPF_WORDALIGN(pflogh.length);
181
182   if (pflogh.subrulenr == (guint32) -1)
183     snprintf(rulestr, sizeof(rulestr), "%u",
184              pflogh.rulenr);
185   else
186     snprintf(rulestr, sizeof(rulestr), "%u.%s.%u",
187              pflogh.rulenr, pflogh.ruleset, pflogh.subrulenr);
188
189   if (hdrlen < MIN_PFLOG_HDRLEN) {
190     if (tree) {
191       ti = proto_tree_add_protocol_format(tree, proto_pflog, tvb, 0,
192                hdrlen, "PF Log invalid header length (%u)", hdrlen);
193     }
194     if (check_col(pinfo->cinfo, COL_INFO)) {
195       col_prepend_fstr(pinfo->cinfo, COL_INFO, "Invalid header length %u",
196           hdrlen);
197     }
198     return;
199   }
200
201   if (tree) {
202     ti = proto_tree_add_protocol_format(tree, proto_pflog, tvb, 0,
203              hdrlen,
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)"),
207              pflogh.ifname,
208              rulestr);
209     pflog_tree = proto_item_add_subtree(ti, ett_pflog);
210
211     proto_tree_add_uint(pflog_tree, hf_pflog_length, tvb,
212              offsetof(struct pfloghdr, length), sizeof(pflogh.length),
213              pflogh.length);
214     proto_tree_add_uint(pflog_tree, hf_pflog_af, tvb,
215              offsetof(struct pfloghdr, af), sizeof(pflogh.af),
216              pflogh.af);
217     proto_tree_add_uint(pflog_tree, hf_pflog_action, tvb,
218              offsetof(struct pfloghdr, action), sizeof(pflogh.action),
219              pflogh.action);
220     proto_tree_add_uint(pflog_tree, hf_pflog_reason, tvb,
221              offsetof(struct pfloghdr, reason), sizeof(pflogh.reason),
222              pflogh.reason);
223     proto_tree_add_string(pflog_tree, hf_pflog_ifname, tvb,
224              offsetof(struct pfloghdr, ifname), sizeof(pflogh.ifname),
225              pflogh.ifname);
226     proto_tree_add_string(pflog_tree, hf_pflog_ruleset, tvb,
227              offsetof(struct pfloghdr, ruleset), sizeof(pflogh.ruleset),
228              pflogh.ruleset);
229     proto_tree_add_int(pflog_tree, hf_pflog_rulenr, tvb,
230              offsetof(struct pfloghdr, rulenr), sizeof(pflogh.rulenr),
231              pflogh.rulenr);
232     proto_tree_add_int(pflog_tree, hf_pflog_subrulenr, tvb,
233              offsetof(struct pfloghdr, subrulenr), sizeof(pflogh.subrulenr),
234              pflogh.subrulenr);
235     proto_tree_add_uint(pflog_tree, hf_pflog_dir, tvb,
236              offsetof(struct pfloghdr, dir), sizeof(pflogh.dir),
237              pflogh.dir);
238   }
239
240   /* Set the tvbuff for the payload after the header */
241   next_tvb = tvb_new_subset(tvb, hdrlen, -1, -1);
242
243   switch (pflogh.af) {
244
245   case BSD_PF_INET:
246     call_dissector(ip_handle, next_tvb, pinfo, tree);
247     break;
248
249   case BSD_PF_INET6:
250     call_dissector(ipv6_handle, next_tvb, pinfo, tree);
251     break;
252
253   default:
254     call_dissector(data_handle, next_tvb, pinfo, tree);
255     break;
256   }
257
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)"),
261         pflogh.ifname,
262         rulestr);
263   }
264 }
265
266 void
267 proto_register_pflog(void)
268 {
269   static hf_register_info hf[] = {
270     { &hf_pflog_length,
271       { "Header Length", "pflog.length", FT_UINT8, BASE_DEC, NULL, 0x0,
272         "Length of Header", HFILL }},
273     { &hf_pflog_af,
274       { "Address Family", "pflog.af", FT_UINT32, BASE_DEC, VALS(af_vals), 0x0,
275         "Protocol (IPv4 vs IPv6)", HFILL }},
276     { &hf_pflog_action,
277       { "Action", "pflog.action", FT_UINT8, BASE_DEC, VALS(action_vals), 0x0,
278         "Action taken by PF on the packet", HFILL }},
279     { &hf_pflog_reason,
280       { "Reason", "pflog.reason", FT_UINT8, BASE_DEC, VALS(reason_vals), 0x0,
281         "Reason for logging the packet", HFILL }},
282     { &hf_pflog_ifname,
283       { "Interface", "pflog.ifname", FT_STRING, BASE_NONE, NULL, 0x0,
284         "Interface", HFILL }},
285     { &hf_pflog_ruleset,
286       { "Ruleset", "pflog.ruleset", FT_STRING, BASE_NONE, NULL, 0x0,
287         "Ruleset name in anchor", HFILL }},
288     { &hf_pflog_rulenr,
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 }},
294     { &hf_pflog_dir,
295       { "Direction", "pflog.dir", FT_UINT8, BASE_DEC, VALS(dir_vals), 0x0,
296         "Direction of packet in stack (inbound versus outbound)", HFILL }},
297   };
298   static gint *ett[] = { &ett_pflog };
299
300   proto_pflog = proto_register_protocol("OpenBSD Packet Filter log file",
301                                         "PFLOG", "pflog");
302   proto_register_field_array(proto_pflog, hf, array_length(hf));
303   proto_register_subtree_array(ett, array_length(ett));
304 }
305
306 void
307 proto_reg_handoff_pflog(void)
308 {
309   dissector_handle_t pflog_handle;
310
311   ip_handle = find_dissector("ip");
312   ipv6_handle = find_dissector("ipv6");
313   data_handle = find_dissector("data");
314
315   pflog_handle = create_dissector_handle(dissect_pflog, proto_pflog);
316   dissector_add("wtap_encap", WTAP_ENCAP_PFLOG, pflog_handle);
317 }
318
319
320 void
321 capture_old_pflog(const guchar *pd, int offset, int len, packet_counts *ld)
322 {
323   struct old_pfloghdr pflogh;
324
325   if (!BYTES_ARE_IN_FRAME(offset, len, (int)OLD_PFLOG_HDRLEN)) {
326     ld->other++;
327     return;
328   }
329
330   offset += OLD_PFLOG_HDRLEN;
331
332   /* Copy out the pflog header to insure alignment */
333   memcpy(&pflogh, pd, sizeof(pflogh));
334   pflogh.af = g_ntohl(pflogh.af);
335
336   switch (pflogh.af) {
337
338   case BSD_PF_INET:
339     capture_ip(pd, offset, len, ld);
340     break;
341
342 #ifdef notyet
343   case BSD_PF_INET6:
344     capture_ipv6(pd, offset, len, ld);
345     break;
346 #endif
347
348   default:
349     ld->other++;
350     break;
351   }
352 }
353
354 static void
355 dissect_old_pflog(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
356 {
357   struct old_pfloghdr pflogh;
358   tvbuff_t *next_tvb;
359   proto_tree *pflog_tree;
360   proto_item *ti;
361
362   if (check_col(pinfo->cinfo, COL_PROTOCOL))
363     col_set_str(pinfo->cinfo, COL_PROTOCOL, "PFLOG-OLD");
364
365   /* Copy out the pflog header to insure alignment */
366   tvb_memcpy(tvb, (guint8 *)&pflogh, 0, sizeof(pflogh));
367
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);
374
375   if (tree) {
376     ti = proto_tree_add_protocol_format(tree, proto_old_pflog, tvb, 0,
377              OLD_PFLOG_HDRLEN,
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)"),
381              pflogh.ifname,
382              pflogh.rnr);
383     pflog_tree = proto_item_add_subtree(ti, ett_pflog);
384
385     proto_tree_add_uint(pflog_tree, hf_old_pflog_af, tvb,
386              offsetof(struct old_pfloghdr, af), sizeof(pflogh.af),
387              pflogh.af);
388     proto_tree_add_int(pflog_tree, hf_old_pflog_rnr, tvb,
389              offsetof(struct old_pfloghdr, rnr), sizeof(pflogh.rnr),
390              pflogh.rnr);
391     proto_tree_add_string(pflog_tree, hf_old_pflog_ifname, tvb,
392              offsetof(struct old_pfloghdr, ifname), sizeof(pflogh.ifname),
393              pflogh.ifname);
394     proto_tree_add_uint(pflog_tree, hf_old_pflog_reason, tvb,
395              offsetof(struct old_pfloghdr, reason), sizeof(pflogh.reason),
396              pflogh.reason);
397     proto_tree_add_uint(pflog_tree, hf_old_pflog_action, tvb,
398              offsetof(struct old_pfloghdr, action), sizeof(pflogh.action),
399              pflogh.action);
400     proto_tree_add_uint(pflog_tree, hf_old_pflog_dir, tvb,
401              offsetof(struct old_pfloghdr, dir), sizeof(pflogh.dir),
402              pflogh.dir);
403   }
404
405   /* Set the tvbuff for the payload after the header */
406   next_tvb = tvb_new_subset(tvb, OLD_PFLOG_HDRLEN, -1, -1);
407
408   switch (pflogh.af) {
409
410   case BSD_PF_INET:
411     call_dissector(ip_handle, next_tvb, pinfo, tree);
412     break;
413
414   case BSD_PF_INET6:
415     call_dissector(ipv6_handle, next_tvb, pinfo, tree);
416     break;
417
418   default:
419     call_dissector(data_handle, next_tvb, pinfo, tree);
420     break;
421   }
422
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)"),
426         pflogh.ifname,
427         pflogh.rnr);
428   }
429 }
430
431 void
432 proto_register_old_pflog(void)
433 {
434   static hf_register_info hf[] = {
435     { &hf_old_pflog_af,
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 }},
441     { &hf_old_pflog_rnr,
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 }},
450     { &hf_old_pflog_dir,
451       { "Direction", "pflog.dir", FT_UINT16, BASE_DEC, VALS(old_dir_vals), 0x0,
452         "Direction of packet in stack (inbound versus outbound)", HFILL }},
453   };
454   static gint *ett[] = { &ett_old_pflog };
455
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));
461 }
462
463 void
464 proto_reg_handoff_old_pflog(void)
465 {
466   dissector_handle_t pflog_handle;
467
468   ip_handle = find_dissector("ip");
469   ipv6_handle = find_dissector("ipv6");
470   data_handle = find_dissector("data");
471
472   pflog_handle = create_dissector_handle(dissect_old_pflog, proto_old_pflog);
473   dissector_add("wtap_encap", WTAP_ENCAP_OLD_PFLOG, pflog_handle);
474 }
475