2 * Copyright 2011,2012 Jakub Zawadzki <darkjames-ws@darkjames.pl>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #define NEW_PROTO_TREE_API
31 #include <epan/packet.h>
32 #include <epan/prefs.h>
33 #include <epan/aftypes.h>
35 /* nfulnl_attr_type enum from <linux/netfilter/nfnetlink_log.h> */
36 enum ws_nfulnl_attr_type
{
39 WS_NFULA_MARK
, /* __u32 nfmark */
40 WS_NFULA_TIMESTAMP
, /* nfulnl_msg_packet_timestamp */
41 WS_NFULA_IFINDEX_INDEV
, /* __u32 ifindex */
42 WS_NFULA_IFINDEX_OUTDEV
, /* __u32 ifindex */
43 WS_NFULA_IFINDEX_PHYSINDEV
, /* __u32 ifindex */
44 WS_NFULA_IFINDEX_PHYSOUTDEV
, /* __u32 ifindex */
45 WS_NFULA_HWADDR
, /* nfulnl_msg_packet_hw */
46 WS_NFULA_PAYLOAD
, /* opaque data payload */
47 WS_NFULA_PREFIX
, /* string prefix */
48 WS_NFULA_UID
, /* user id of socket */
49 WS_NFULA_SEQ
, /* instance-local sequence number */
50 WS_NFULA_SEQ_GLOBAL
, /* global sequence number */
51 WS_NFULA_GID
, /* group id of socket */
52 WS_NFULA_HWTYPE
, /* hardware type */
53 WS_NFULA_HWHEADER
, /* hardware header */
54 WS_NFULA_HWLEN
/* hardware header length */
57 #define BYTE_ORDER_AUTO 0
58 #define BYTE_ORDER_BE 1
59 #define BYTE_ORDER_LE 2
60 #define BYTE_ORDER_HOST 3
62 static const enum_val_t byte_order_types
[] = {
63 { "Auto", "Auto", BYTE_ORDER_AUTO
},
64 { "Host", "Host", BYTE_ORDER_HOST
},
65 { "LE", "Little Endian", BYTE_ORDER_LE
},
66 { "BE", "Big Endian", BYTE_ORDER_BE
},
70 static const value_string _linux_family_vals
[] = {
71 { LINUX_AF_INET
, "IP" },
72 { LINUX_AF_INET6
, "IPv6" },
76 static const value_string _encoding_vals
[] = {
77 { ENC_BIG_ENDIAN
, "Big Endian" },
78 { ENC_LITTLE_ENDIAN
, "Little Endian" },
79 /* { ENC_NA, "Unknown" }, */ /* ENC_NA has the same value as ENC_BIG_ENDIAN */
83 static const value_string nflog_tlv_vals
[] = {
84 { WS_NFULA_UNSPEC
, "NFULA_UNSPEC" },
85 { WS_NFULA_PACKET_HDR
, "NFULA_PACKET_HDR" },
86 { WS_NFULA_MARK
, "NFULA_MARK" },
87 { WS_NFULA_TIMESTAMP
, "NFULA_TIMESTAMP" },
88 { WS_NFULA_IFINDEX_INDEV
, "NFULA_IFINDEX_INDEV" },
89 { WS_NFULA_IFINDEX_OUTDEV
, "NFULA_IFINDEX_OUTDEV" },
90 { WS_NFULA_IFINDEX_PHYSINDEV
, "NFULA_IFINDEX_PHYSINDEV" },
91 { WS_NFULA_IFINDEX_PHYSOUTDEV
, "NFULA_IFINDEX_PHYSOUTDEV" },
92 { WS_NFULA_HWADDR
, "NFULA_HWADDR" },
93 { WS_NFULA_PAYLOAD
, "NFULA_PAYLOAD" },
94 { WS_NFULA_PREFIX
, "NFULA_PREFIX" },
95 { WS_NFULA_UID
, "NFULA_UID" },
96 { WS_NFULA_SEQ
, "NFULA_SEQ" },
97 { WS_NFULA_SEQ_GLOBAL
, "NFULA_SEQ_GLOBAL" },
98 { WS_NFULA_GID
, "NFULA_GID" },
99 { WS_NFULA_HWTYPE
, "NFULA_HWTYPE" },
100 { WS_NFULA_HWHEADER
, "NFULA_HWHEADER" },
101 { WS_NFULA_HWLEN
, "NFULA_HWLEN" },
105 static gint nflog_byte_order
= BYTE_ORDER_AUTO
;
107 static int ett_nflog
= -1;
108 static int ett_nflog_tlv
= -1;
110 static header_field_info
*hfi_nflog
= NULL
;
112 #define NFLOG_HFI_INIT HFI_INIT(proto_nflog)
115 static header_field_info hfi_nflog_family NFLOG_HFI_INIT
=
116 { "Family", "nflog.family", FT_UINT8
, BASE_DEC
, VALS(_linux_family_vals
), 0x00, NULL
, HFILL
};
118 static header_field_info hfi_nflog_version NFLOG_HFI_INIT
=
119 { "Version", "nflog.version", FT_UINT8
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
};
121 static header_field_info hfi_nflog_resid NFLOG_HFI_INIT
=
122 { "Resource id", "nflog.res_id", FT_UINT16
, BASE_DEC
, NULL
, 0x00, NULL
, HFILL
};
124 static header_field_info hfi_nflog_encoding NFLOG_HFI_INIT
=
125 { "Encoding", "nflog.encoding", FT_UINT32
, BASE_HEX
, VALS(_encoding_vals
), 0x00, NULL
, HFILL
};
128 static header_field_info hfi_nflog_tlv NFLOG_HFI_INIT
=
129 { "TLV", "nflog.tlv", FT_BYTES
, BASE_NONE
, NULL
, 0x00, NULL
, HFILL
};
131 static header_field_info hfi_nflog_tlv_length NFLOG_HFI_INIT
=
132 { "Length", "nflog.tlv_length", FT_UINT16
, BASE_DEC
, NULL
, 0x00, "TLV Length", HFILL
};
134 static header_field_info hfi_nflog_tlv_type NFLOG_HFI_INIT
=
135 { "Type", "nflog.tlv_type", FT_UINT16
, BASE_DEC
, VALS(nflog_tlv_vals
), 0x7fff, "TLV Type", HFILL
};
138 static header_field_info hfi_nflog_tlv_prefix NFLOG_HFI_INIT
=
139 { "Prefix", "nflog.prefix", FT_STRINGZ
, BASE_NONE
, NULL
, 0x00, "TLV Prefix Value", HFILL
};
141 static header_field_info hfi_nflog_tlv_uid NFLOG_HFI_INIT
=
142 { "UID", "nflog.uid", FT_INT32
, BASE_DEC
, NULL
, 0x00, "TLV UID Value", HFILL
};
144 static header_field_info hfi_nflog_tlv_gid NFLOG_HFI_INIT
=
145 { "GID", "nflog.gid", FT_INT32
, BASE_DEC
, NULL
, 0x00, "TLV GID Value", HFILL
};
147 static header_field_info hfi_nflog_tlv_timestamp NFLOG_HFI_INIT
=
148 { "Timestamp", "nflog.timestamp", FT_ABSOLUTE_TIME
, ABSOLUTE_TIME_LOCAL
, NULL
, 0x00, "TLV Timestamp Value", HFILL
};
150 static header_field_info hfi_nflog_tlv_unknown NFLOG_HFI_INIT
=
151 { "Value", "nflog.tlv_value", FT_BYTES
, BASE_NONE
, NULL
, 0x00, "TLV Value", HFILL
};
153 static dissector_handle_t ip_handle
;
154 static dissector_handle_t ip6_handle
;
155 static dissector_handle_t data_handle
;
158 nflog_tvb_test_order(tvbuff_t
*tvb
, int offset
, guint16 (*val16_get
)(tvbuff_t
*, int))
160 while (tvb_length_remaining(tvb
, offset
) > 4) {
161 guint16 tlv_len
= val16_get(tvb
, offset
+ 0);
168 tlv_type
= (val16_get(tvb
, offset
+ 2) & 0x7fff);
170 if (tlv_type
>= 0x100)
176 offset
+= ((tlv_len
+ 3) & ~3); /* next TLV aligned to 4B */
182 nflog_tvb_byte_order(tvbuff_t
*tvb
, int tlv_offset
)
184 switch (nflog_byte_order
) {
186 return ENC_BIG_ENDIAN
;
189 return ENC_LITTLE_ENDIAN
;
191 case BYTE_ORDER_HOST
:
192 return (G_BYTE_ORDER
== G_LITTLE_ENDIAN
) ?
197 if (nflog_tvb_test_order(tvb
, tlv_offset
, tvb_get_ntohs
))
198 return ENC_BIG_ENDIAN
;
200 if (nflog_tvb_test_order(tvb
, tlv_offset
, tvb_get_letohs
))
201 return ENC_LITTLE_ENDIAN
;
203 return ENC_NA
; /* ENC_NA same as ENC_BIG_ENDIAN */
207 dissect_nflog(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
209 const int start_tlv_offset
= 4;
211 proto_tree
*nflog_tree
= NULL
;
216 tvbuff_t
*next_tvb
= NULL
;
220 guint16 (*val16_get
)(tvbuff_t
*, int);
222 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "NFLOG");
223 col_clear(pinfo
->cinfo
, COL_INFO
);
225 aftype
= tvb_get_guint8(tvb
, 0);
226 enc
= nflog_tvb_byte_order(tvb
, start_tlv_offset
);
228 case ENC_LITTLE_ENDIAN
:
229 val16_get
= tvb_get_letohs
;
234 val16_get
= tvb_get_ntohs
;
239 if (proto_field_is_referenced(tree
, hfi_nflog
->id
)) {
240 ti
= proto_tree_add_item(tree
, hfi_nflog
, tvb
, 0, -1, ENC_NA
);
241 nflog_tree
= proto_item_add_subtree(ti
, ett_nflog
);
243 proto_tree_add_item(nflog_tree
, &hfi_nflog_family
, tvb
, offset
, 1, ENC_NA
);
246 proto_tree_add_item(nflog_tree
, &hfi_nflog_version
, tvb
, offset
, 1, ENC_NA
);
249 proto_tree_add_item(nflog_tree
, &hfi_nflog_resid
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
252 ti
= proto_tree_add_uint(nflog_tree
, &hfi_nflog_encoding
,
253 tvb
, offset
, tvb_length_remaining(tvb
, offset
), enc
);
254 PROTO_ITEM_SET_GENERATED(ti
);
257 offset
= start_tlv_offset
;
259 while (tvb_length_remaining(tvb
, offset
) >= 4) {
260 guint16 tlv_len
= val16_get(tvb
, offset
+ 0);
264 proto_tree
*tlv_tree
;
270 value_len
= tlv_len
- 4;
271 tlv_type
= (val16_get(tvb
, offset
+ 2) & 0x7fff);
274 gboolean handled
= FALSE
;
276 ti
= proto_tree_add_bytes_format(nflog_tree
, hfi_nflog_tlv
.id
,
277 tvb
, offset
, tlv_len
, NULL
,
278 "TLV Type: %s (%u), Length: %u",
279 val_to_str_const(tlv_type
, nflog_tlv_vals
, "Unknown"),
281 tlv_tree
= proto_item_add_subtree(ti
, ett_nflog_tlv
);
283 proto_tree_add_item(tlv_tree
, &hfi_nflog_tlv_length
, tvb
, offset
+ 0, 2, enc
);
284 proto_tree_add_item(tlv_tree
, &hfi_nflog_tlv_type
, tvb
, offset
+ 2, 2, enc
);
286 case WS_NFULA_PAYLOAD
:
290 case WS_NFULA_PREFIX
:
291 if (value_len
>= 1) {
292 proto_tree_add_item(tlv_tree
, &hfi_nflog_tlv_prefix
,
293 tvb
, offset
+ 4, value_len
, ENC_NA
);
299 if (value_len
== 4) {
300 proto_tree_add_item(tlv_tree
, &hfi_nflog_tlv_uid
,
301 tvb
, offset
+ 4, value_len
, ENC_BIG_ENDIAN
);
307 if (value_len
== 4) {
308 proto_tree_add_item(tlv_tree
, &hfi_nflog_tlv_gid
,
309 tvb
, offset
+ 4, value_len
, ENC_BIG_ENDIAN
);
314 case WS_NFULA_TIMESTAMP
:
315 if (value_len
== 16) {
318 ts
.secs
= (time_t)tvb_get_ntoh64(tvb
, offset
+ 4);
319 /* XXX - add an "expert info" warning if this is >= 10^9? */
320 ts
.nsecs
= (int)tvb_get_ntoh64(tvb
, offset
+ 12);
321 proto_tree_add_time(tlv_tree
, &hfi_nflog_tlv_timestamp
,
322 tvb
, offset
+ 4, value_len
, &ts
);
329 proto_tree_add_item(tlv_tree
, &hfi_nflog_tlv_unknown
,
330 tvb
, offset
+ 4, value_len
, ENC_NA
);
333 if (tlv_type
== WS_NFULA_PAYLOAD
)
334 next_tvb
= tvb_new_subset(tvb
, offset
+ 4, value_len
, value_len
);
336 offset
+= ((tlv_len
+ 3) & ~3); /* next TLV aligned to 4B */
342 call_dissector(ip_handle
, next_tvb
, pinfo
, tree
);
345 call_dissector(ip6_handle
, next_tvb
, pinfo
, tree
);
348 call_dissector(data_handle
, next_tvb
, pinfo
, tree
);
355 proto_register_nflog(void)
357 #ifndef HAVE_HFI_SECTION_INIT
358 static header_field_info
*hfi
[] = {
366 &hfi_nflog_tlv_length
,
369 &hfi_nflog_tlv_prefix
,
372 &hfi_nflog_tlv_timestamp
,
373 &hfi_nflog_tlv_unknown
,
377 static gint
*ett
[] = {
386 proto_nflog
= proto_register_protocol("Linux Netfilter NFLOG", "NFLOG", "nflog");
387 hfi_nflog
= proto_registrar_get_nth(proto_nflog
);
389 pref
= prefs_register_protocol(proto_nflog
, NULL
);
390 prefs_register_enum_preference(pref
, "byte_order_type", "Byte Order", "Byte Order",
391 &nflog_byte_order
, byte_order_types
, FALSE
);
393 register_dissector("nflog", dissect_nflog
, proto_nflog
);
395 proto_register_fields(proto_nflog
, hfi
, array_length(hfi
));
396 proto_register_subtree_array(ett
, array_length(ett
));
401 proto_reg_handoff_nflog(void)
403 dissector_handle_t nflog_handle
;
405 ip_handle
= find_dissector("ip");
406 ip6_handle
= find_dissector("ipv6");
407 data_handle
= find_dissector("data");
409 nflog_handle
= find_dissector("nflog");
410 dissector_add_uint("wtap_encap", WTAP_ENCAP_NFLOG
, nflog_handle
);