For proto_tree_add_item(..., proto_xxx, ...)use ENC_NA as the encoding arg.
[obnox/wireshark/wip.git] / epan / dissectors / 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 /* Specifications... :
32 http://www.openbsd.org/cgi-bin/cvsweb/src/sys/net/if_pflog.c
33 http://www.openbsd.org/cgi-bin/cvsweb/src/sys/net/if_pflog.h
34 */
35 #ifdef HAVE_CONFIG_H
36 # include "config.h"
37 #endif
38
39 #include <epan/packet.h>
40
41 #include <epan/aftypes.h>
42 #include <epan/etypes.h>
43 #include <epan/addr_resolv.h>
44 #include <epan/expert.h>
45
46 static dissector_handle_t  data_handle, ip_handle, ipv6_handle;
47
48 /* header fields */
49 static int proto_pflog = -1;
50 static int hf_pflog_length = -1;
51 static int hf_pflog_af = -1;
52 static int hf_pflog_action = -1;
53 static int hf_pflog_reason = -1;
54 static int hf_pflog_ifname = -1;
55 static int hf_pflog_ruleset = -1;
56 static int hf_pflog_rulenr = -1;
57 static int hf_pflog_subrulenr = -1;
58 static int hf_pflog_uid = -1;
59 static int hf_pflog_pid = -1;
60 static int hf_pflog_rule_uid = -1;
61 static int hf_pflog_rule_pid = -1;
62 static int hf_pflog_dir = -1;
63 static int hf_pflog_rewritten = -1;
64 static int hf_pflog_pad = -1;
65 static int hf_pflog_saddr_ipv4 = -1;
66 static int hf_pflog_daddr_ipv4 = -1;
67 static int hf_pflog_saddr_ipv6 = -1;
68 static int hf_pflog_daddr_ipv6 = -1;
69 static int hf_pflog_saddr = -1;
70 static int hf_pflog_daddr = -1;
71 static int hf_pflog_sport = -1;
72 static int hf_pflog_dport = -1;
73 static gint ett_pflog = -1;
74
75 /* old header */
76 static int proto_old_pflog = -1;
77 static int hf_old_pflog_af = -1;
78 static int hf_old_pflog_ifname = -1;
79 static int hf_old_pflog_rnr = -1;
80 static int hf_old_pflog_reason = -1;
81 static int hf_old_pflog_action = -1;
82 static int hf_old_pflog_dir = -1;
83
84 static gint ett_old_pflog = -1;
85
86 #define LEN_PFLOG_BSD34 48
87 #define LEN_PFLOG_BSD38 64
88 #define LEN_PFLOG_BSD49 100
89
90 static const value_string pflog_af_vals[] = {
91   { BSD_AF_INET, "IPv4" },
92   { BSD_AF_INET6_BSD, "IPv6" },
93   { 0, NULL }
94 };
95
96 static const value_string pflog_reason_vals[] = {
97   { 0, "match" },
98   { 1, "bad-offset" },
99   { 2, "fragment" },
100   { 3, "short" },
101   { 4, "normalize" },
102   { 5, "memory" },
103   { 6, "timestamp" },
104   { 7, "congestion" },
105   { 8, "ip-option" },
106   { 9, "proto-cksum" },
107   { 10, "state-mismatch" },
108   { 11, "state-ins-fail" },
109   { 12, "max-states" },
110   { 13, "srcnode-limit" },
111   { 14, "syn-proxy" },
112   { 0, NULL }
113 };
114
115 /* Actions */
116 enum    { PF_PASS, PF_DROP, PF_SCRUB, PF_NOSCRUB, PF_NAT, PF_NONAT,
117           PF_BINAT, PF_NOBINAT, PF_RDR, PF_NORDR, PF_SYNPROXY_DROP, PF_DEFER,
118           PF_MATCH, PF_DIVERT, PF_RT };
119
120 static const value_string pflog_action_vals[] = {
121   { PF_MATCH, "match" },
122   { PF_SCRUB, "scrub" },
123   { PF_PASS,  "pass" },
124   { PF_DROP,  "block" },
125   { PF_DIVERT, "divert" },
126   { PF_NAT,   "nat" },
127   { PF_NONAT, "nat" },
128   { PF_BINAT, "binat" },
129   { PF_NOBINAT, "binat" },
130   { PF_RDR,   "rdr" },
131   { PF_NORDR, "rdr" },
132   { 0,        NULL }
133 };
134
135 /* Directions */
136 #define PF_OLD_IN  0
137 #define PF_OLD_OUT 1
138
139 #define PF_INOUT 0
140 #define PF_IN    1
141 #define PF_OUT   2
142
143 static const value_string pflog_old_dir_vals[] = {
144   { PF_OLD_IN,  "in" },
145   { PF_OLD_OUT, "out" },
146   { 0,          NULL }
147 };
148
149 static const value_string pflog_dir_vals[] = {
150   { PF_INOUT, "inout" },
151   { PF_IN,    "in" },
152   { PF_OUT,   "out" },
153   { 0,        NULL }
154 };
155
156 static void
157 dissect_pflog(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
158 {
159   tvbuff_t *next_tvb;
160   proto_tree *pflog_tree = NULL;
161   proto_item *ti = NULL, *ti_len;
162   int length;
163   guint8 af, action;
164   guint8 *ifname;
165   guint32 rulenr;
166   guint8 pad_len = 3;
167   gint offset = 0;
168
169   col_set_str(pinfo->cinfo, COL_PROTOCOL, "PFLOG");
170
171   if (tree) {
172     ti = proto_tree_add_item(tree, proto_pflog, tvb, offset, 0, ENC_NA);
173
174     pflog_tree = proto_item_add_subtree(ti, ett_pflog);
175   }
176   length = tvb_get_guint8(tvb, offset) + pad_len;
177
178   ti_len = proto_tree_add_item(pflog_tree, hf_pflog_length, tvb, offset, 1, ENC_BIG_ENDIAN);
179   if(length < LEN_PFLOG_BSD34)
180   {
181     expert_add_info_format(pinfo, ti_len, PI_MALFORMED, PI_ERROR, "Invalid header length %u", length);
182   }
183
184   offset += 1;
185
186   proto_tree_add_item(pflog_tree, hf_pflog_af, tvb, offset, 1, ENC_BIG_ENDIAN);
187   af = tvb_get_guint8(tvb, offset);
188   offset += 1;
189
190   proto_tree_add_item(pflog_tree, hf_pflog_action, tvb, offset, 1, ENC_BIG_ENDIAN);
191   action = tvb_get_guint8(tvb, offset);
192   offset += 1;
193
194   proto_tree_add_item(pflog_tree, hf_pflog_reason, tvb, offset, 1, ENC_BIG_ENDIAN);
195   offset += 1;
196
197   proto_tree_add_item(pflog_tree, hf_pflog_ifname, tvb, offset, 16, ENC_ASCII|ENC_NA);
198   ifname = tvb_get_ephemeral_string(tvb, offset, 16);
199   offset += 16;
200
201   proto_tree_add_item(pflog_tree, hf_pflog_ruleset, tvb, offset, 16, ENC_ASCII|ENC_NA);
202   offset += 16;
203
204   proto_tree_add_item(pflog_tree, hf_pflog_rulenr, tvb, offset, 4, ENC_BIG_ENDIAN);
205   rulenr = tvb_get_ntohs(tvb, offset);
206   offset += 4;
207
208   proto_tree_add_item(pflog_tree, hf_pflog_subrulenr, tvb, offset, 4, ENC_BIG_ENDIAN);
209   offset += 4;
210
211   if(length >= LEN_PFLOG_BSD38)
212   {
213     proto_tree_add_item(pflog_tree, hf_pflog_uid, tvb, offset, 4, ENC_BIG_ENDIAN);
214     offset += 4;
215
216     proto_tree_add_item(pflog_tree, hf_pflog_pid, tvb, offset, 4, ENC_BIG_ENDIAN);
217     offset += 4;
218
219     proto_tree_add_item(pflog_tree, hf_pflog_rule_uid, tvb, offset, 4, ENC_BIG_ENDIAN);
220     offset += 4;
221
222     proto_tree_add_item(pflog_tree, hf_pflog_rule_pid, tvb, offset, 4, ENC_BIG_ENDIAN);
223     offset += 4;
224   }
225   proto_tree_add_item(pflog_tree, hf_pflog_dir, tvb, offset, 1, ENC_BIG_ENDIAN);
226   offset += 1;
227
228   if(length >= LEN_PFLOG_BSD49)
229   {
230     pad_len = 2;
231     length -= 3; /* With OpenBSD >= 4.8 the length is the length of full Header (with padding..) */
232     proto_tree_add_item(pflog_tree, hf_pflog_rewritten, tvb, offset, 1, ENC_BIG_ENDIAN);
233     offset += 1;
234   }
235
236   proto_tree_add_item(pflog_tree, hf_pflog_pad, tvb, offset, pad_len, ENC_NA);
237   offset += pad_len;
238
239   if(length >= LEN_PFLOG_BSD49)
240   {
241     switch (af) {
242
243     case BSD_AF_INET:
244       proto_tree_add_item(pflog_tree, hf_pflog_saddr_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN);
245       offset += 16;
246
247       proto_tree_add_item(pflog_tree, hf_pflog_daddr_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN);
248       offset += 16;
249       break;
250
251     case BSD_AF_INET6_BSD:
252       proto_tree_add_item(pflog_tree, hf_pflog_saddr_ipv6, tvb, offset, 16, ENC_NA);
253       offset += 16;
254
255       proto_tree_add_item(pflog_tree, hf_pflog_daddr_ipv6, tvb, offset, 16, ENC_NA);
256       offset += 16;
257       break;
258
259     default:
260       proto_tree_add_item(pflog_tree, hf_pflog_saddr, tvb, offset, 16, ENC_NA);
261       offset += 16;
262
263       proto_tree_add_item(pflog_tree, hf_pflog_daddr, tvb, offset, 16, ENC_NA);
264       offset += 16;
265       break;
266     }
267
268     proto_tree_add_item(pflog_tree, hf_pflog_sport, tvb, offset, 2, ENC_BIG_ENDIAN);
269     offset += 2;
270
271     proto_tree_add_item(pflog_tree, hf_pflog_dport, tvb, offset, 2, ENC_BIG_ENDIAN);
272     offset += 2;
273   }
274
275   proto_item_set_text(ti, "PF Log %s %s on %s by rule %u",
276     val_to_str(af, pflog_af_vals, "unknown (%u)"),
277     val_to_str(action, pflog_action_vals, "unknown (%u)"),
278     ifname,
279     rulenr);
280   proto_item_set_len(ti, offset);
281
282
283
284   /* Set the tvbuff for the payload after the header */
285   next_tvb = tvb_new_subset_remaining(tvb, length);
286
287   switch (af) {
288
289   case BSD_AF_INET:
290     call_dissector(ip_handle, next_tvb, pinfo, tree);
291     break;
292
293   case BSD_AF_INET6_BSD:
294     call_dissector(ipv6_handle, next_tvb, pinfo, tree);
295     break;
296
297   default:
298     call_dissector(data_handle, next_tvb, pinfo, tree);
299     break;
300   }
301
302   if (check_col(pinfo->cinfo, COL_INFO)) {
303     col_prepend_fstr(pinfo->cinfo, COL_INFO, "[%s %s/%u] ",
304         val_to_str(action, pflog_action_vals, "unknown (%u)"),
305         ifname,
306         rulenr);
307   }
308 }
309
310 void
311 proto_register_pflog(void)
312 {
313   static hf_register_info hf[] = {
314     { &hf_pflog_length,
315       { "Header Length", "pflog.length", FT_UINT8, BASE_DEC, NULL, 0x0,
316         "Length of Header", HFILL }},
317     { &hf_pflog_af,
318       { "Address Family", "pflog.af", FT_UINT32, BASE_DEC, VALS(pflog_af_vals), 0x0,
319         "Protocol (IPv4 vs IPv6)", HFILL }},
320     { &hf_pflog_action,
321       { "Action", "pflog.action", FT_UINT8, BASE_DEC, VALS(pflog_action_vals), 0x0,
322         "Action taken by PF on the packet", HFILL }},
323     { &hf_pflog_reason,
324       { "Reason", "pflog.reason", FT_UINT8, BASE_DEC, VALS(pflog_reason_vals), 0x0,
325         "Reason for logging the packet", HFILL }},
326     { &hf_pflog_ifname,
327       { "Interface", "pflog.ifname", FT_STRING, BASE_NONE, NULL, 0x0,
328         NULL, HFILL }},
329     { &hf_pflog_ruleset,
330       { "Ruleset", "pflog.ruleset", FT_STRING, BASE_NONE, NULL, 0x0,
331         "Ruleset name in anchor", HFILL }},
332     { &hf_pflog_rulenr,
333       { "Rule Number", "pflog.rulenr", FT_INT32, BASE_DEC, NULL, 0x0,
334         "Last matched firewall main ruleset rule number", HFILL }},
335     { &hf_pflog_subrulenr,
336       { "Sub Rule Number", "pflog.subrulenr", FT_INT32, BASE_DEC, NULL, 0x0,
337         "Last matched firewall anchored ruleset rule number", HFILL }},
338     { &hf_pflog_uid,
339       { "UID", "pflog.uid", FT_INT32, BASE_DEC, NULL, 0x0,
340         NULL, HFILL }},
341     { &hf_pflog_pid,
342       { "PID", "pflog.pid", FT_INT32, BASE_DEC, NULL, 0x0,
343         NULL, HFILL }},
344     { &hf_pflog_rule_uid,
345       { "Rule UID", "pflog.rule_uid", FT_INT32, BASE_DEC, NULL, 0x0,
346         NULL, HFILL }},
347     { &hf_pflog_rule_pid,
348       { "Rule PID", "pflog.rule_pid", FT_INT32, BASE_DEC, NULL, 0x0,
349         NULL, HFILL }},
350     { &hf_pflog_rewritten,
351       { "Rewritten", "pflog.rewritten", FT_UINT8, BASE_DEC, NULL, 0x0,
352         NULL, HFILL }},
353     { &hf_pflog_pad,
354       { "Padding", "pflog.pad", FT_BYTES, BASE_NONE, NULL, 0x0,
355         "Must be Zero", HFILL }},
356     { &hf_pflog_saddr_ipv4,
357       { "Source Address", "pflog.saddr", FT_IPv4, BASE_NONE, NULL, 0x0,
358         NULL, HFILL }},
359     { &hf_pflog_daddr_ipv4,
360       { "Destination Address", "pflog.daddr", FT_IPv4, BASE_NONE, NULL, 0x0,
361         NULL, HFILL }},
362     { &hf_pflog_saddr_ipv6,
363       { "Source Address", "pflog.saddr", FT_IPv6, BASE_NONE, NULL, 0x0,
364         NULL, HFILL }},
365     { &hf_pflog_daddr_ipv6,
366       { "Destination Address", "pflog.daddr", FT_IPv6, BASE_NONE, NULL, 0x0,
367         NULL, HFILL }},
368     { &hf_pflog_saddr,
369       { "Source Address", "pflog.saddr", FT_BYTES, BASE_NONE, NULL, 0x0,
370         NULL, HFILL }},
371     { &hf_pflog_daddr,
372       { "Destination Address", "pflog.daddr", FT_BYTES, BASE_NONE, NULL, 0x0,
373         NULL, HFILL }},
374     { &hf_pflog_sport,
375       { "Source Port", "pflog.sport", FT_UINT16, BASE_DEC, NULL, 0x0,
376         NULL, HFILL }},
377     { &hf_pflog_dport,
378       { "Destination Port", "pflog.dport", FT_UINT16, BASE_DEC, NULL, 0x0,
379         NULL, HFILL }},
380     { &hf_pflog_dir,
381       { "Direction", "pflog.dir", FT_UINT8, BASE_DEC, VALS(pflog_dir_vals), 0x0,
382         "Direction of packet in stack (inbound versus outbound)", HFILL }},
383   };
384   static gint *ett[] = { &ett_pflog };
385
386   proto_pflog = proto_register_protocol("OpenBSD Packet Filter log file",
387                                         "PFLOG", "pflog");
388   proto_register_field_array(proto_pflog, hf, array_length(hf));
389   proto_register_subtree_array(ett, array_length(ett));
390 }
391
392 void
393 proto_reg_handoff_pflog(void)
394 {
395   dissector_handle_t pflog_handle;
396
397   ip_handle = find_dissector("ip");
398   ipv6_handle = find_dissector("ipv6");
399   data_handle = find_dissector("data");
400
401   pflog_handle = create_dissector_handle(dissect_pflog, proto_pflog);
402   dissector_add_uint("wtap_encap", WTAP_ENCAP_PFLOG, pflog_handle);
403 }
404
405 static int
406 dissect_old_pflog(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
407 {
408   tvbuff_t *next_tvb;
409   proto_tree *pflog_tree = NULL;
410   proto_item *ti = NULL;
411   guint32 af;
412   guint8 *ifname;
413   guint16 rnr, action;
414   gint offset = 0;
415
416   col_set_str(pinfo->cinfo, COL_PROTOCOL, "PFLOG-OLD");
417
418   if (tree) {
419     ti = proto_tree_add_item(tree, proto_old_pflog, tvb, 0, 0, ENC_NA);
420
421     pflog_tree = proto_item_add_subtree(ti, ett_pflog);
422
423     proto_tree_add_item(pflog_tree, hf_old_pflog_af, tvb, offset, 4, ENC_BIG_ENDIAN);
424   }
425   af = tvb_get_ntohl(tvb, offset);
426   offset +=4;
427
428   if (tree) {
429     proto_tree_add_item(pflog_tree, hf_old_pflog_ifname, tvb, offset, 16, ENC_ASCII|ENC_NA);
430   }
431   ifname = tvb_get_ephemeral_string(tvb, offset, 16);
432   offset +=16;
433
434   if (tree) {
435     proto_tree_add_item(pflog_tree, hf_old_pflog_rnr, tvb, offset, 2, ENC_BIG_ENDIAN);
436   }
437   rnr = tvb_get_ntohs(tvb, offset);
438   offset +=2;
439
440   if (tree) {
441     proto_tree_add_item(pflog_tree, hf_old_pflog_reason, tvb, offset, 2, ENC_BIG_ENDIAN);
442   }
443   offset +=2;
444
445   if (tree) {
446     proto_tree_add_item(pflog_tree, hf_old_pflog_action, tvb, offset, 2, ENC_BIG_ENDIAN);
447   }
448   action = tvb_get_ntohs(tvb, offset);
449   offset +=2;
450
451   if (tree) {
452     proto_tree_add_item(pflog_tree, hf_old_pflog_dir, tvb, offset, 2, ENC_BIG_ENDIAN);
453   }
454   offset +=2;
455
456   if (tree) {
457     proto_item_set_text(ti, "PF Log (pre 3.4) %s %s on %s by rule %d",
458       val_to_str(af, pflog_af_vals, "unknown (%u)"),
459       val_to_str(action, pflog_action_vals, "unknown (%u)"),
460       ifname,
461       rnr);
462     proto_item_set_len(ti, offset);
463
464   }
465
466   /* Set the tvbuff for the payload after the header */
467   next_tvb = tvb_new_subset_remaining(tvb, offset);
468
469   switch (af) {
470
471   case BSD_AF_INET:
472     offset += call_dissector(ip_handle, next_tvb, pinfo, tree);
473     break;
474
475   case BSD_AF_INET6_BSD:
476     offset += call_dissector(ipv6_handle, next_tvb, pinfo, tree);
477     break;
478
479   default:
480     offset += call_dissector(data_handle, next_tvb, pinfo, tree);
481     break;
482   }
483
484   if (check_col(pinfo->cinfo, COL_INFO)) {
485     col_prepend_fstr(pinfo->cinfo, COL_INFO, "[%s %s/#%d] ",
486         val_to_str(action, pflog_action_vals, "unknown (%u)"),
487         ifname,
488         rnr);
489   }
490   return offset;
491 }
492
493 void
494 proto_register_old_pflog(void)
495 {
496   static hf_register_info hf[] = {
497     { &hf_old_pflog_af,
498       { "Address Family", "pflog.af", FT_UINT32, BASE_DEC, VALS(pflog_af_vals), 0x0,
499         "Protocol (IPv4 vs IPv6)", HFILL }},
500     { &hf_old_pflog_ifname,
501       { "Interface", "pflog.ifname", FT_STRING, BASE_NONE, NULL, 0x0,
502         NULL, HFILL }},
503     { &hf_old_pflog_rnr,
504       { "Rule Number", "pflog.rnr", FT_INT16, BASE_DEC, NULL, 0x0,
505         "Last matched firewall rule number", HFILL }},
506     { &hf_old_pflog_reason,
507       { "Reason", "pflog.reason", FT_UINT16, BASE_DEC, VALS(pflog_reason_vals), 0x0,
508         "Reason for logging the packet", HFILL }},
509     { &hf_old_pflog_action,
510       { "Action", "pflog.action", FT_UINT16, BASE_DEC, VALS(pflog_action_vals), 0x0,
511         "Action taken by PF on the packet", HFILL }},
512     { &hf_old_pflog_dir,
513       { "Direction", "pflog.dir", FT_UINT16, BASE_DEC, VALS(pflog_old_dir_vals), 0x0,
514         "Direction of packet in stack (inbound versus outbound)", HFILL }},
515   };
516   static gint *ett[] = { &ett_old_pflog };
517
518   proto_old_pflog = proto_register_protocol(
519           "OpenBSD Packet Filter log file, pre 3.4",
520           "PFLOG-OLD", "pflog-old");
521   proto_register_field_array(proto_old_pflog, hf, array_length(hf));
522   proto_register_subtree_array(ett, array_length(ett));
523 }
524
525 void
526 proto_reg_handoff_old_pflog(void)
527 {
528   dissector_handle_t pflog_handle;
529
530   ip_handle = find_dissector("ip");
531   ipv6_handle = find_dissector("ipv6");
532   data_handle = find_dissector("data");
533
534   pflog_handle = new_create_dissector_handle(dissect_old_pflog, proto_old_pflog);
535   dissector_add_uint("wtap_encap", WTAP_ENCAP_OLD_PFLOG, pflog_handle);
536 }
537 /*
538  * Editor modelines
539  *
540  * Local Variables:
541  * c-basic-offset: 2
542  * tab-width: 8
543  * indent-tabs-mode: nil
544  * End:
545  *
546  * ex: set shiftwidth=2 tabstop=8 expandtab:
547  * :indentSize=2:tabSize=8:noTabs=true:
548  */