2 * Copyright 2011,2012 Jakub Zawadzki <darkjames-ws@darkjames.pl>
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
8 * SPDX-License-Identifier: GPL-2.0-or-later
12 #include <epan/etypes.h>
13 #include <epan/packet.h>
14 #include <wiretap/wtap.h>
15 #include <wsutil/ws_roundup.h>
17 #include "packet-netlink.h"
19 void proto_register_nflog(void);
20 void proto_reg_handoff_nflog(void);
22 /* nfulnl_attr_type enum from <linux/netfilter/nfnetlink_log.h> */
23 enum ws_nfulnl_attr_type
{
26 WS_NFULA_MARK
, /* __u32 nfmark */
27 WS_NFULA_TIMESTAMP
, /* nfulnl_msg_packet_timestamp */
28 WS_NFULA_IFINDEX_INDEV
, /* __u32 ifindex */
29 WS_NFULA_IFINDEX_OUTDEV
, /* __u32 ifindex */
30 WS_NFULA_IFINDEX_PHYSINDEV
, /* __u32 ifindex */
31 WS_NFULA_IFINDEX_PHYSOUTDEV
, /* __u32 ifindex */
32 WS_NFULA_HWADDR
, /* nfulnl_msg_packet_hw */
33 WS_NFULA_PAYLOAD
, /* opaque data payload */
34 WS_NFULA_PREFIX
, /* string prefix */
35 WS_NFULA_UID
, /* user id of socket */
36 WS_NFULA_SEQ
, /* instance-local sequence number */
37 WS_NFULA_SEQ_GLOBAL
, /* global sequence number */
38 WS_NFULA_GID
, /* group id of socket */
39 WS_NFULA_HWTYPE
, /* hardware type */
40 WS_NFULA_HWHEADER
, /* hardware header */
41 WS_NFULA_HWLEN
/* hardware header length */
44 static const value_string nflog_tlv_vals
[] = {
45 { WS_NFULA_UNSPEC
, "NFULA_UNSPEC" },
46 { WS_NFULA_PACKET_HDR
, "NFULA_PACKET_HDR" },
47 { WS_NFULA_MARK
, "NFULA_MARK" },
48 { WS_NFULA_TIMESTAMP
, "NFULA_TIMESTAMP" },
49 { WS_NFULA_IFINDEX_INDEV
, "NFULA_IFINDEX_INDEV" },
50 { WS_NFULA_IFINDEX_OUTDEV
, "NFULA_IFINDEX_OUTDEV" },
51 { WS_NFULA_IFINDEX_PHYSINDEV
, "NFULA_IFINDEX_PHYSINDEV" },
52 { WS_NFULA_IFINDEX_PHYSOUTDEV
, "NFULA_IFINDEX_PHYSOUTDEV" },
53 { WS_NFULA_HWADDR
, "NFULA_HWADDR" },
54 { WS_NFULA_PAYLOAD
, "NFULA_PAYLOAD" },
55 { WS_NFULA_PREFIX
, "NFULA_PREFIX" },
56 { WS_NFULA_UID
, "NFULA_UID" },
57 { WS_NFULA_SEQ
, "NFULA_SEQ" },
58 { WS_NFULA_SEQ_GLOBAL
, "NFULA_SEQ_GLOBAL" },
59 { WS_NFULA_GID
, "NFULA_GID" },
60 { WS_NFULA_HWTYPE
, "NFULA_HWTYPE" },
61 { WS_NFULA_HWHEADER
, "NFULA_HWHEADER" },
62 { WS_NFULA_HWLEN
, "NFULA_HWLEN" },
66 static int proto_nflog
;
68 static int hf_nflog_family
;
69 static int hf_nflog_resid
;
70 static int hf_nflog_tlv
;
71 static int hf_nflog_tlv_gid
;
72 static int hf_nflog_tlv_hook
;
73 static int hf_nflog_tlv_hwprotocol
;
74 static int hf_nflog_tlv_ifindex_indev
;
75 static int hf_nflog_tlv_ifindex_outdev
;
76 static int hf_nflog_tlv_ifindex_physindev
;
77 static int hf_nflog_tlv_ifindex_physoutdev
;
78 static int hf_nflog_tlv_length
;
79 static int hf_nflog_tlv_prefix
;
80 static int hf_nflog_tlv_timestamp
;
81 static int hf_nflog_tlv_type
;
82 static int hf_nflog_tlv_uid
;
83 static int hf_nflog_tlv_unknown
;
84 static int hf_nflog_version
;
87 static int ett_nflog_tlv
;
89 static dissector_handle_t ip_handle
;
90 static dissector_handle_t ip6_handle
;
91 static dissector_table_t ethertype_table
;
92 static dissector_handle_t nflog_handle
;
95 dissect_nflog(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
97 const int start_tlv_offset
= 4;
99 proto_tree
*nflog_tree
= NULL
;
104 tvbuff_t
*next_tvb
= NULL
;
106 uint16_t hw_protocol
= 0;
108 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "NFLOG");
109 col_clear(pinfo
->cinfo
, COL_INFO
);
111 pf
= tvb_get_uint8(tvb
, 0);
114 if (proto_field_is_referenced(tree
, proto_nflog
)) {
115 ti
= proto_tree_add_item(tree
, proto_nflog
, tvb
, 0, -1, ENC_NA
);
116 nflog_tree
= proto_item_add_subtree(ti
, ett_nflog
);
118 proto_tree_add_item(nflog_tree
, hf_nflog_family
, tvb
, offset
, 1, ENC_NA
);
121 proto_tree_add_item(nflog_tree
, hf_nflog_version
, tvb
, offset
, 1, ENC_NA
);
124 proto_tree_add_item(nflog_tree
, hf_nflog_resid
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
128 offset
= start_tlv_offset
;
130 while (tvb_reported_length_remaining(tvb
, offset
) >= 4) {
131 uint16_t tlv_len
= tvb_get_h_uint16(tvb
, offset
+ 0);
135 proto_tree
*tlv_tree
;
141 value_len
= tlv_len
- 4;
142 tlv_type
= (tvb_get_h_uint16(tvb
, offset
+ 2) & 0x7fff);
145 bool handled
= false;
147 ti
= proto_tree_add_bytes_format(nflog_tree
, hf_nflog_tlv
,
148 tvb
, offset
, tlv_len
, NULL
,
149 "TLV Type: %s (%u), Length: %u",
150 val_to_str_const(tlv_type
, nflog_tlv_vals
, "Unknown"),
152 tlv_tree
= proto_item_add_subtree(ti
, ett_nflog_tlv
);
154 proto_tree_add_item(tlv_tree
, hf_nflog_tlv_length
, tvb
, offset
+ 0, 2, ENC_HOST_ENDIAN
);
155 proto_tree_add_item(tlv_tree
, hf_nflog_tlv_type
, tvb
, offset
+ 2, 2, ENC_HOST_ENDIAN
);
157 case WS_NFULA_PACKET_HDR
:
158 if (value_len
== 4) {
159 proto_tree_add_item(tlv_tree
, hf_nflog_tlv_hwprotocol
,
160 tvb
, offset
+ 4, 2, ENC_BIG_ENDIAN
);
161 proto_tree_add_item(tlv_tree
, hf_nflog_tlv_hook
,
162 tvb
, offset
+ 6, 1, ENC_NA
);
167 case WS_NFULA_IFINDEX_INDEV
:
168 if (value_len
== 4) {
169 proto_tree_add_item(tlv_tree
, hf_nflog_tlv_ifindex_indev
, tvb
, offset
+ 4, value_len
, ENC_BIG_ENDIAN
);
174 case WS_NFULA_IFINDEX_OUTDEV
:
175 if (value_len
== 4) {
176 proto_tree_add_item(tlv_tree
, hf_nflog_tlv_ifindex_outdev
, tvb
, offset
+ 4, value_len
, ENC_BIG_ENDIAN
);
181 case WS_NFULA_IFINDEX_PHYSINDEV
:
182 if (value_len
== 4) {
183 proto_tree_add_item(tlv_tree
, hf_nflog_tlv_ifindex_physindev
, tvb
, offset
+ 4, value_len
, ENC_BIG_ENDIAN
);
188 case WS_NFULA_IFINDEX_PHYSOUTDEV
:
189 if (value_len
== 4) {
190 proto_tree_add_item(tlv_tree
, hf_nflog_tlv_ifindex_physoutdev
, tvb
, offset
+ 4, value_len
, ENC_BIG_ENDIAN
);
195 case WS_NFULA_PAYLOAD
:
199 case WS_NFULA_PREFIX
:
200 if (value_len
>= 1) {
201 proto_tree_add_item(tlv_tree
, hf_nflog_tlv_prefix
,
202 tvb
, offset
+ 4, value_len
, ENC_ASCII
);
208 if (value_len
== 4) {
209 proto_tree_add_item(tlv_tree
, hf_nflog_tlv_uid
,
210 tvb
, offset
+ 4, value_len
, ENC_BIG_ENDIAN
);
216 if (value_len
== 4) {
217 proto_tree_add_item(tlv_tree
, hf_nflog_tlv_gid
,
218 tvb
, offset
+ 4, value_len
, ENC_BIG_ENDIAN
);
223 case WS_NFULA_TIMESTAMP
:
224 if (value_len
== 16) {
226 * 64-bit seconds and 64-bit microseconds.
228 * XXX - add an "expert info" warning if the
229 * microseconds are >= 10^6?
231 proto_tree_add_item(tlv_tree
, hf_nflog_tlv_timestamp
,
232 tvb
, offset
+ 4, value_len
,
233 ENC_TIME_SECS_USECS
|ENC_BIG_ENDIAN
);
240 proto_tree_add_item(tlv_tree
, hf_nflog_tlv_unknown
,
241 tvb
, offset
+ 4, value_len
, ENC_NA
);
244 if (tlv_type
== WS_NFULA_PACKET_HDR
&& value_len
== 4)
245 hw_protocol
= tvb_get_ntohs(tvb
, offset
+ 4);
246 if (tlv_type
== WS_NFULA_PAYLOAD
)
247 next_tvb
= tvb_new_subset_length(tvb
, offset
+ 4, value_len
);
249 offset
+= WS_ROUNDUP_4(tlv_len
); /* next TLV aligned to 4B */
252 if (next_tvb
&& hw_protocol
) {
253 if (!dissector_try_uint(ethertype_table
, hw_protocol
, next_tvb
, pinfo
, tree
))
254 call_data_dissector(next_tvb
, pinfo
, tree
);
255 } else if (next_tvb
) {
257 /* Note: NFPROTO_INET is not supposed to appear here, it is mapped
258 * to NFPROTO_IPV4 or NFPROTO_IPV6 */
259 case WS_NFPROTO_IPV4
:
260 call_dissector(ip_handle
, next_tvb
, pinfo
, tree
);
262 case WS_NFPROTO_IPV6
:
263 call_dissector(ip6_handle
, next_tvb
, pinfo
, tree
);
266 call_data_dissector(next_tvb
, pinfo
, tree
);
270 return tvb_captured_length(tvb
);
274 proto_register_nflog(void)
276 static hf_register_info hf
[] = {
278 { "Family", "nflog.family",
279 FT_UINT8
, BASE_DEC
, VALS(nfproto_family_vals
), 0x00,
283 { "Version", "nflog.version",
284 FT_UINT8
, BASE_DEC
, NULL
, 0x00,
288 { "Resource id", "nflog.res_id",
289 FT_UINT16
, BASE_DEC
, NULL
, 0x00,
293 { "TLV", "nflog.tlv",
294 FT_BYTES
, BASE_NONE
, NULL
, 0x00,
297 { &hf_nflog_tlv_length
,
298 { "Length", "nflog.tlv_length",
299 FT_UINT16
, BASE_DEC
, NULL
, 0x00,
300 "TLV Length", HFILL
}
302 { &hf_nflog_tlv_type
,
303 { "Type", "nflog.tlv_type",
304 FT_UINT16
, BASE_DEC
, VALS(nflog_tlv_vals
), 0x7fff,
307 { &hf_nflog_tlv_hwprotocol
,
308 { "HW protocol", "nflog.protocol",
309 FT_UINT16
, BASE_HEX
, VALS(etype_vals
), 0x00,
312 { &hf_nflog_tlv_hook
,
313 { "Netfilter hook", "nflog.hook",
314 FT_UINT8
, BASE_DEC
, VALS(netfilter_hooks_vals
), 0x00,
317 { &hf_nflog_tlv_ifindex_indev
,
318 { "IFINDEX_INDEV", "nflog.ifindex_indev",
319 FT_UINT32
, BASE_DEC
, NULL
, 0x00,
322 { &hf_nflog_tlv_ifindex_outdev
,
323 { "IFINDEX_OUTDEV", "nflog.ifindex_outdev",
324 FT_UINT32
, BASE_DEC
, NULL
, 0x00,
327 { &hf_nflog_tlv_ifindex_physindev
,
328 { "IFINDEX_PHYSINDEV", "nflog.ifindex_physindev",
329 FT_UINT32
, BASE_DEC
, NULL
, 0x00,
332 { &hf_nflog_tlv_ifindex_physoutdev
,
333 { "IFINDEX_PHYSOUTDEV", "nflog.ifindex_physoutdev",
334 FT_UINT32
, BASE_DEC
, NULL
, 0x00,
337 { &hf_nflog_tlv_prefix
,
338 { "Prefix", "nflog.prefix",
339 FT_STRINGZ
, BASE_NONE
, NULL
, 0x00,
340 "TLV Prefix Value", HFILL
}
343 { "UID", "nflog.uid",
344 FT_INT32
, BASE_DEC
, NULL
, 0x00,
345 "TLV UID Value", HFILL
}
348 { "GID", "nflog.gid",
349 FT_INT32
, BASE_DEC
, NULL
, 0x00,
350 "TLV GID Value", HFILL
}
352 { &hf_nflog_tlv_timestamp
,
353 { "Timestamp", "nflog.timestamp",
354 FT_ABSOLUTE_TIME
, ABSOLUTE_TIME_LOCAL
, NULL
, 0x00,
355 "TLV Timestamp Value", HFILL
}
357 { &hf_nflog_tlv_unknown
,
358 { "Value", "nflog.tlv_value",
359 FT_BYTES
, BASE_NONE
, NULL
, 0x00,
364 static int *ett
[] = {
369 proto_nflog
= proto_register_protocol("Linux Netfilter NFLOG", "NFLOG", "nflog");
371 nflog_handle
= register_dissector("nflog", dissect_nflog
, proto_nflog
);
373 proto_register_field_array(proto_nflog
, hf
, array_length(hf
));
374 proto_register_subtree_array(ett
, array_length(ett
));
379 proto_reg_handoff_nflog(void)
381 ip_handle
= find_dissector_add_dependency("ip", proto_nflog
);
382 ip6_handle
= find_dissector_add_dependency("ipv6", proto_nflog
);
384 dissector_add_uint("wtap_encap", WTAP_ENCAP_NFLOG
, nflog_handle
);
385 ethertype_table
= find_dissector_table("ethertype");
394 * indent-tabs-mode: nil
397 * ex: set shiftwidth=4 tabstop=8 expandtab:
398 * :indentSize=4:tabSize=8:noTabs=true: