netlink-netfilter: add partial ipset support
[metze/wireshark/wip.git] / epan / dissectors / packet-netlink-netfilter.c
1 /* packet-netlink-netfilter.c
2  *
3  * Wireshark - Network traffic analyzer
4  * By Gerald Combs <gerald@wireshark.org>
5  * Copyright 1998 Gerald Combs
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #define NEW_PROTO_TREE_API
23
24 #include "config.h"
25
26 #include <epan/aftypes.h>
27 #include <epan/etypes.h>
28 #include <epan/packet.h>
29 #include "packet-netlink.h"
30
31 void proto_register_netlink_netfilter(void);
32 void proto_reg_handoff_netlink_netfilter(void);
33
34 typedef struct {
35         packet_info *pinfo;
36         struct packet_netlink_data *data;
37
38         int encoding; /* copy of data->encoding */
39
40         guint16 hw_protocol; /* protocol for NFQUEUE packet payloads. */
41 } netlink_netfilter_info_t;
42
43
44 static dissector_handle_t netlink_netfilter;
45 static dissector_handle_t nflog_handle;
46 static dissector_table_t ethertype_table;
47
48 static header_field_info *hfi_netlink_netfilter = NULL;
49
50 #define NETLINK_NETFILTER_HFI_INIT HFI_INIT(proto_netlink_netfilter)
51
52 /* nfnetlink subsystems from <linux/netfilter/nfnetlink.h> */
53 enum {
54         WS_NFNL_SUBSYS_NONE              =  0,
55         WS_NFNL_SUBSYS_CTNETLINK         =  1,
56         WS_NFNL_SUBSYS_CTNETLINK_EXP     =  2,
57         WS_NFNL_SUBSYS_QUEUE             =  3,
58         WS_NFNL_SUBSYS_ULOG              =  4,
59         WS_NFNL_SUBSYS_OSF               =  5,
60         WS_NFNL_SUBSYS_IPSET             =  6,
61         WS_NFNL_SUBSYS_ACCT              =  7,
62         WS_NFNL_SUBSYS_CTNETLINK_TIMEOUT =  8,
63         WS_NFNL_SUBSYS_CTHELPER          =  9,
64         WS_NFNL_SUBSYS_NFTABLES          = 10,
65         WS_NFNL_SUBSYS_NFT_COMPAT        = 11,
66 };
67
68 /* nfnetlink ULOG subsystem types from <linux/netfilter/nfnetlink_log.h> */
69 enum ws_nfulnl_msg_types {
70         WS_NFULNL_MSG_PACKET = 0,
71         WS_NFULNL_MSG_CONFIG = 1
72 };
73
74 /* Macros for "hook function responses" from <linux/netfilter.h> */
75 enum ws_verdict_types {
76         WS_NF_DROP      = 0,
77         WS_NF_ACCEPT    = 1,
78         WS_NF_STOLEN    = 2,
79         WS_NF_QUEUE     = 3,
80         WS_NF_REPEAT    = 4,
81         WS_NF_STOP      = 5,
82 };
83
84 enum ws_nf_inet_hooks {
85         WS_NF_INET_PRE_ROUTING  = 0,
86         WS_NF_INET_LOCAL_IN     = 1,
87         WS_NF_INET_FORWARD      = 2,
88         WS_NF_INET_LOCAL_OUT    = 3,
89         WS_NF_INET_POST_ROUTING = 4,
90 };
91
92 /* from <linux/netfilter/nf_conntrack_common.h> */
93 enum ws_ip_conntrack_info {
94         WS_IP_CT_ESTABLISHED,
95         WS_IP_CT_RELATED,
96         WS_IP_CT_NEW,
97         WS_IP_CT_IS_REPLY,
98         WS_IP_CT_ESTABLISHED_REPLY = WS_IP_CT_ESTABLISHED + WS_IP_CT_IS_REPLY,
99         WS_IP_CT_RELATED_REPLY = WS_IP_CT_RELATED + WS_IP_CT_IS_REPLY,
100         WS_IP_CT_NUMBER,
101 };
102
103 /* nfnetlink QUEUE subsystem types from <linux/netfilter/nfnetlink_queue.h> */
104 enum ws_nfqnl_msg_types {
105         WS_NFQNL_MSG_PACKET         = 0,
106         WS_NFQNL_MSG_VERDICT        = 1,
107         WS_NFQNL_MSG_CONFIG         = 2,
108         WS_NFQNL_MSG_VERDICT_BATCH  = 3
109 };
110
111 enum ws_nfqnl_attr_type {
112         WS_NFQA_UNSPEC              = 0,
113         WS_NFQA_PACKET_HDR          = 1,
114         WS_NFQA_VERDICT_HDR         = 2,
115         WS_NFQA_MARK                = 3,
116         WS_NFQA_TIMESTAMP           = 4,
117         WS_NFQA_IFINDEX_INDEV       = 5,
118         WS_NFQA_IFINDEX_OUTDEV      = 6,
119         WS_NFQA_IFINDEX_PHYSINDEV   = 7,
120         WS_NFQA_IFINDEX_PHYSOUTDEV  = 8,
121         WS_NFQA_HWADDR              = 9,
122         WS_NFQA_PAYLOAD             = 10,
123         WS_NFQA_CT                  = 11,
124         WS_NFQA_CT_INFO             = 12,
125         WS_NFQA_CAP_LEN             = 13,
126         WS_NFQA_SKB_INFO            = 14,
127         WS_NFQA_EXP                 = 15,
128         WS_NFQA_UID                 = 16,
129         WS_NFQA_GID                 = 17,
130         WS_NFQA_SECCTX              = 18,
131         WS_NFQA_VLAN                = 19,
132         WS_NFQA_L2HDR               = 20,
133 };
134
135 enum ws_nfqnl_msg_config_cmds {
136         WS_NFQNL_CFG_CMD_NONE       = 0,
137         WS_NFQNL_CFG_CMD_BIND       = 1,
138         WS_NFQNL_CFG_CMD_UNBIND     = 2,
139         WS_NFQNL_CFG_CMD_PF_BIND    = 3,
140         WS_NFQNL_CFG_CMD_PF_UNBIND  = 4,
141 };
142
143 enum ws_nfqnl_config_mode {
144         WS_NFQNL_COPY_NONE          = 0,
145         WS_NFQNL_COPY_META          = 1,
146         WS_NFQNL_COPY_PACKET        = 2,
147 };
148
149 enum ws_nfqnl_attr_config {
150         WS_NFQA_CFG_UNSPEC          = 0,
151         WS_NFQA_CFG_CMD             = 1,
152         WS_NFQA_CFG_PARAMS          = 2,
153         WS_NFQA_CFG_QUEUE_MAXLEN    = 3,
154         WS_NFQA_CFG_MASK            = 4,
155         WS_NFQA_CFG_FLAGS           = 5,
156 };
157
158 /* from <linux/netfilter/ipset/ip_set.h> */
159 enum ws_ipset_cmd {
160         WS_IPSET_CMD_NONE           = 0,
161         WS_IPSET_CMD_PROTOCOL       = 1,
162         WS_IPSET_CMD_CREATE         = 2,
163         WS_IPSET_CMD_DESTROY        = 3,
164         WS_IPSET_CMD_FLUSH          = 4,
165         WS_IPSET_CMD_RENAME         = 5,
166         WS_IPSET_CMD_SWAP           = 6,
167         WS_IPSET_CMD_LIST           = 7,
168         WS_IPSET_CMD_SAVE           = 8,
169         WS_IPSET_CMD_ADD            = 9,
170         WS_IPSET_CMD_DEL            = 10,
171         WS_IPSET_CMD_TEST           = 11,
172         WS_IPSET_CMD_HEADER         = 12,
173         WS_IPSET_CMD_TYPE           = 13,
174 };
175
176 /* Attributes at command level */
177 enum ws_ipset_attr {
178         WS_IPSET_ATTR_PROTOCOL      = 1,
179         WS_IPSET_ATTR_SETNAME       = 2,
180         WS_IPSET_ATTR_TYPENAME      = 3,
181         WS_IPSET_ATTR_REVISION      = 4,
182         WS_IPSET_ATTR_FAMILY        = 5,
183         WS_IPSET_ATTR_FLAGS         = 6,
184         WS_IPSET_ATTR_DATA          = 7,
185         WS_IPSET_ATTR_ADT           = 8,
186         WS_IPSET_ATTR_LINENO        = 9,
187         WS_IPSET_ATTR_PROTOCOL_MIN  = 10,
188 };
189
190 /* CADT-specific attributes (Create/Abstract Data Type) */
191 enum ws_ipset_cadt_attr {
192         WS_IPSET_ATTR_IP_FROM           = 1,
193         WS_IPSET_ATTR_IP_TO             = 2,
194         WS_IPSET_ATTR_CIDR              = 3,
195         WS_IPSET_ATTR_PORT_FROM         = 4,
196         WS_IPSET_ATTR_PORT_TO           = 5,
197         WS_IPSET_ATTR_TIMEOUT           = 6,
198         WS_IPSET_ATTR_PROTO             = 7,
199         WS_IPSET_ATTR_CADT_FLAGS        = 8,
200         WS_IPSET_ATTR_CADT_LINENO       = 9,
201         WS_IPSET_ATTR_MARK              = 10,
202         WS_IPSET_ATTR_MARKMASK          = 11,
203         /* (reserved up to 16) */
204 #define WS_IPSET_ATTR_CADT_MAX            16
205         WS_IPSET_ATTR_GC                = 17,
206         WS_IPSET_ATTR_HASHSIZE          = 18,
207         WS_IPSET_ATTR_MAXELEM           = 19,
208         WS_IPSET_ATTR_NETMASK           = 20,
209         WS_IPSET_ATTR_PROBES            = 21,
210         WS_IPSET_ATTR_RESIZE            = 22,
211         WS_IPSET_ATTR_SIZE              = 23,
212         WS_IPSET_ATTR_ELEMENTS          = 24,
213         WS_IPSET_ATTR_REFERENCES        = 25,
214         WS_IPSET_ATTR_MEMSIZE           = 26,
215 };
216
217 /* ADT-specific attrivutes */
218 enum ws_ipset_adt_attr {
219         WS_IPSET_ATTR_ETHER             = 17,
220         WS_IPSET_ATTR_NAME              = 18,
221         WS_IPSET_ATTR_NAMEREF           = 19,
222         WS_IPSET_ATTR_IP2               = 20,
223         WS_IPSET_ATTR_CIDR2             = 21,
224         WS_IPSET_ATTR_IP2_TO            = 22,
225         WS_IPSET_ATTR_IFACE             = 23,
226         WS_IPSET_ATTR_BYTES             = 24,
227         WS_IPSET_ATTR_PACKETS           = 25,
228         WS_IPSET_ATTR_COMMENT           = 26,
229         WS_IPSET_ATTR_SKBMARK           = 27,
230         WS_IPSET_ATTR_SKBPRIO           = 28,
231         WS_IPSET_ATTR_SKBQUEUE          = 29,
232         WS_IPSET_ATTR_PAD               = 30,
233 };
234
235 /* IP specific attributes */
236 enum ws_ipset_ip_attr {
237         WS_IPSET_ATTR_IPADDR_IPV4       = 1,
238         WS_IPSET_ATTR_IPADDR_IPV6       = 2,
239 };
240
241
242 static int ett_netlink_netfilter = -1;
243 static int ett_nfq_config_attr = -1;
244 static int ett_nfq_attr = -1;
245 static int ett_ipset_attr = -1;
246 static int ett_ipset_cadt_attr = -1;
247 static int ett_ipset_adt_attr = -1;
248 static int ett_ipset_ip_attr = -1;
249
250 /* nfgenmsg header, common to all Netfilter over Netlink packets. */
251
252 static header_field_info hfi_netlink_netfilter_family NETLINK_NETFILTER_HFI_INIT =
253         { "Address family", "netlink-netfilter.family", FT_UINT8, BASE_DEC | BASE_EXT_STRING,
254           &linux_af_vals_ext, 0x00, "nfnetlink address family", HFILL };
255
256 static header_field_info hfi_netlink_netfilter_version NETLINK_NETFILTER_HFI_INIT =
257         { "Version", "netlink-netfilter.version", FT_UINT8, BASE_DEC,
258           NULL, 0x00, "nfnetlink version", HFILL };
259
260 static header_field_info hfi_netlink_netfilter_resid NETLINK_NETFILTER_HFI_INIT =
261         { "Resource id", "netlink-netfilter.res_id", FT_UINT16, BASE_DEC,
262           NULL, 0x00, NULL, HFILL };
263
264 static int dissect_netlink_netfilter_header(tvbuff_t *tvb, proto_tree *tree, int offset)
265 {
266         proto_tree_add_item(tree, &hfi_netlink_netfilter_family, tvb, offset, 1, ENC_NA);
267         offset++;
268
269         proto_tree_add_item(tree, &hfi_netlink_netfilter_version, tvb, offset, 1, ENC_NA);
270         offset++;
271
272         proto_tree_add_item(tree, &hfi_netlink_netfilter_resid, tvb, offset, 2, ENC_BIG_ENDIAN);
273         offset += 2;
274
275         return offset;
276 }
277
278 /* QUEUE */
279
280 /* QUEUE - Config */
281
282 static const value_string nfq_type_vals[] = {
283         { WS_NFQNL_MSG_PACKET,          "Packet" },
284         { WS_NFQNL_MSG_VERDICT,         "Verdict" },
285         { WS_NFQNL_MSG_CONFIG,          "Config" },
286         { WS_NFQNL_MSG_VERDICT_BATCH,   "Verdict (batch)" },
287         { 0, NULL }
288 };
289
290 static const value_string nfq_config_command_vals[] = {
291         { WS_NFQNL_CFG_CMD_NONE,        "None" },
292         { WS_NFQNL_CFG_CMD_BIND,        "Bind" },
293         { WS_NFQNL_CFG_CMD_UNBIND,      "Unbind" },
294         { WS_NFQNL_CFG_CMD_PF_BIND,     "PF bind" },
295         { WS_NFQNL_CFG_CMD_PF_UNBIND,   "PF unbind" },
296         { 0, NULL }
297 };
298
299 static const value_string nfq_config_attr_vals[] = {
300         { WS_NFQA_CFG_UNSPEC,           "Unspecified" },
301         { WS_NFQA_CFG_CMD,              "Command" },
302         { WS_NFQA_CFG_PARAMS,           "Parameters" },
303         { WS_NFQA_CFG_QUEUE_MAXLEN,     "Maximum queue length" },
304         { WS_NFQA_CFG_MASK,             "Mask" },
305         { WS_NFQA_CFG_FLAGS,            "Flags" },
306         { 0, NULL }
307 };
308
309 static const value_string nfq_config_mode_vals[] = {
310         { WS_NFQNL_COPY_NONE,           "None" },
311         { WS_NFQNL_COPY_META,           "Meta" },
312         { WS_NFQNL_COPY_PACKET,         "Packet" },
313         { 0, NULL }
314 };
315
316 static header_field_info hfi_nfq_config_command_command NETLINK_NETFILTER_HFI_INIT =
317         { "Command", "netlink-netfilter.queue.config.command.command", FT_UINT8, BASE_DEC,
318           VALS(nfq_config_command_vals), 0x00, NULL, HFILL };
319
320 static header_field_info hfi_nfq_config_command_pf NETLINK_NETFILTER_HFI_INIT =
321         { "Protocol family", "netlink-netfilter.queue.config.command.pf", FT_UINT16, BASE_DEC | BASE_EXT_STRING,
322           &linux_af_vals_ext, 0x00, NULL, HFILL };
323
324 static header_field_info hfi_nfq_config_params_copyrange NETLINK_NETFILTER_HFI_INIT =
325         { "Copy range", "netlink-netfilter.queue.config.params.copy_range", FT_UINT32, BASE_HEX,
326           NULL, 0x00, NULL, HFILL };
327
328 static header_field_info hfi_nfq_config_params_copymode NETLINK_NETFILTER_HFI_INIT =
329         { "Copy mode", "netlink-netfilter.queue.config.params.copy_mode", FT_UINT8, BASE_DEC,
330           VALS(nfq_config_mode_vals), 0x00, NULL, HFILL };
331
332 static header_field_info hfi_nfq_config_queue_maxlen NETLINK_NETFILTER_HFI_INIT =
333         { "Maximum queue length", "netlink-netfilter.queue.config.queue_maxlen", FT_UINT32, BASE_DEC,
334           NULL, 0x00, NULL, HFILL };
335
336 static header_field_info hfi_nfq_config_mask NETLINK_NETFILTER_HFI_INIT =
337         { "Flags mask", "netlink-netfilter.queue.config.mask", FT_UINT32, BASE_HEX,
338           NULL, 0x00, NULL, HFILL };
339
340 static header_field_info hfi_nfq_config_flags NETLINK_NETFILTER_HFI_INIT =
341         { "Flags", "netlink-netfilter.queue.config.flags", FT_UINT32, BASE_HEX,
342           NULL, 0x00, NULL, HFILL };
343
344 static int
345 dissect_nfq_config_attrs(tvbuff_t *tvb, void *data, proto_tree *tree, int nla_type, int offset, int len)
346 {
347         enum ws_nfqnl_attr_config type = (enum ws_nfqnl_attr_config) nla_type;
348         netlink_netfilter_info_t *info = (netlink_netfilter_info_t *) data;
349
350         switch (type) {
351                 case WS_NFQA_CFG_UNSPEC:
352                         break;
353
354                 case WS_NFQA_CFG_CMD:
355                         if (len == 4) {
356                                 proto_tree_add_item(tree, &hfi_nfq_config_command_command, tvb, offset, 1, ENC_NA);
357                                 offset += 2; /* skip command and 1 byte padding. */
358
359                                 proto_tree_add_item(tree, &hfi_nfq_config_command_pf, tvb, offset, 2, ENC_BIG_ENDIAN);
360                                 offset += 2;
361                         }
362                         break;
363
364                 case WS_NFQA_CFG_PARAMS:
365                         if (len == 5) {
366                                 proto_tree_add_item(tree, &hfi_nfq_config_params_copyrange, tvb, offset, 4, ENC_BIG_ENDIAN);
367                                 offset += 4;
368
369                                 proto_tree_add_item(tree, &hfi_nfq_config_params_copymode, tvb, offset, 1, ENC_NA);
370                                 offset++;
371                         }
372                         break;
373
374                 case WS_NFQA_CFG_QUEUE_MAXLEN:
375                         if (len == 4) {
376                                 proto_tree_add_item(tree, &hfi_nfq_config_queue_maxlen, tvb, offset, 4, info->encoding);
377                                 offset += 4;
378                         }
379                         break;
380
381                 case WS_NFQA_CFG_MASK:
382                         if (len == 4) {
383                                 proto_tree_add_item(tree, &hfi_nfq_config_mask, tvb, offset, 4, info->encoding);
384                                 offset += 4;
385                         }
386                         break;
387
388                 case WS_NFQA_CFG_FLAGS:
389                         if (len == 4) {
390                                 proto_tree_add_item(tree, &hfi_nfq_config_flags, tvb, offset, 4, info->encoding);
391                                 offset += 4;
392                         }
393                         break;
394         }
395
396         return offset;
397 }
398
399 static header_field_info hfi_nfq_config_attr NETLINK_NETFILTER_HFI_INIT =
400         { "Type", "netlink-netfilter.queue.config_attr", FT_UINT16, BASE_DEC,
401           VALS(nfq_config_attr_vals), NLA_TYPE_MASK, NULL, HFILL };
402
403 /* QUEUE - Packet and verdict */
404
405 static const value_string nfq_attr_vals[] = {
406         { WS_NFQA_UNSPEC,               "Unspecified" },
407         { WS_NFQA_PACKET_HDR,           "Packet header" },
408         { WS_NFQA_VERDICT_HDR,          "Verdict header" },
409         { WS_NFQA_MARK,                 "Mark" },
410         { WS_NFQA_TIMESTAMP,            "Timestamp" },
411         { WS_NFQA_IFINDEX_INDEV,        "NFQA_IFINDEX_INDEV" },
412         { WS_NFQA_IFINDEX_OUTDEV,       "NFQA_IFINDEX_OUTDEV" },
413         { WS_NFQA_IFINDEX_PHYSINDEV,    "NFQA_IFINDEX_PHYSINDEV" },
414         { WS_NFQA_IFINDEX_PHYSOUTDEV,   "NFQA_IFINDEX_PHYSOUTDEV" },
415         { WS_NFQA_HWADDR,               "Hardware address" },
416         { WS_NFQA_PAYLOAD,              "Payload" },
417         { WS_NFQA_CT,                   "NFQA_CT" },
418         { WS_NFQA_CT_INFO,              "Conntrack info" },
419         { WS_NFQA_CAP_LEN,              "Length of captured packet" },
420         { WS_NFQA_SKB_INFO,             "SKB meta information" },
421         { WS_NFQA_EXP,                  "Conntrack expectation" },
422         { WS_NFQA_UID,                  "SK UID" },
423         { WS_NFQA_GID,                  "SK GID" },
424         { WS_NFQA_SECCTX,               "Security context string" },
425         { WS_NFQA_VLAN,                 "Packet VLAN info" },
426         { WS_NFQA_L2HDR,                "Full L2 header" },
427         { 0, NULL }
428 };
429
430 static const value_string nfq_verdict_vals[] = {
431         { WS_NF_DROP,   "DROP" },
432         { WS_NF_ACCEPT, "ACCEPT" },
433         { WS_NF_STOLEN, "STOLEN" },
434         { WS_NF_QUEUE,  "QUEUE" },
435         { WS_NF_REPEAT, "REPEAT" },
436         { WS_NF_STOP,   "STOP" },
437         { 0, NULL }
438 };
439
440 static const value_string nfq_hooks_vals[] = {
441         { WS_NF_INET_PRE_ROUTING,   "Pre-routing" },
442         { WS_NF_INET_LOCAL_IN,      "Local in" },
443         { WS_NF_INET_FORWARD,       "Forward" },
444         { WS_NF_INET_LOCAL_OUT,     "Local out" },
445         { WS_NF_INET_POST_ROUTING,  "Post-routing" },
446         { 0, NULL }
447 };
448
449 static const value_string nfq_ctinfo_vals[] = {
450         { WS_IP_CT_ESTABLISHED,         "ESTABLISHED" },
451         { WS_IP_CT_RELATED,             "RELATED" },
452         { WS_IP_CT_NEW,                 "NEW" },
453         { WS_IP_CT_IS_REPLY,            "IS_REPLY" },
454         { WS_IP_CT_ESTABLISHED_REPLY,   "ESTABLISHED_REPLY" },
455         { WS_IP_CT_RELATED_REPLY,       "RELATED_REPLY" },
456         { WS_IP_CT_NUMBER,              "NUMBER" },
457         { 0, NULL }
458 };
459
460 static header_field_info hfi_nfq_verdict_verdict NETLINK_NETFILTER_HFI_INIT =
461         { "Verdict", "netlink-netfilter.queue.verdict.verdict", FT_UINT32, BASE_DEC,
462           VALS(nfq_verdict_vals), 0x00, NULL, HFILL };
463
464 static header_field_info hfi_nfq_verdict_id NETLINK_NETFILTER_HFI_INIT =
465         { "Packet ID", "netlink-netfilter.queue.verdict.id", FT_UINT32, BASE_DEC,
466           NULL, 0x00, NULL, HFILL };
467
468 static header_field_info hfi_nfq_packet_id NETLINK_NETFILTER_HFI_INIT =
469         { "Packet ID", "netlink-netfilter.queue.packet.id", FT_UINT32, BASE_DEC,
470           NULL, 0x00, NULL, HFILL };
471
472 static header_field_info hfi_nfq_packet_hwprotocol NETLINK_NETFILTER_HFI_INIT =
473         { "HW protocol", "netlink-netfilter.queue.packet.protocol", FT_UINT16, BASE_HEX,
474           VALS(etype_vals), 0x00, NULL, HFILL };
475
476 static header_field_info hfi_nfq_packet_hook NETLINK_NETFILTER_HFI_INIT =
477         { "Netfilter hook", "netlink-netfilter.queue.packet.hook", FT_UINT8, BASE_DEC,
478           VALS(nfq_hooks_vals), 0x00, NULL, HFILL };
479
480 static header_field_info hfi_nfq_nfmark NETLINK_NETFILTER_HFI_INIT =
481         { "Mark", "netlink-netfilter.queue.nfmark", FT_UINT32, BASE_DEC,
482           NULL, 0x00, NULL, HFILL };
483
484 static header_field_info hfi_nfq_timestamp NETLINK_NETFILTER_HFI_INIT =
485         { "Timestamp", "netlink-netfilter.queue.timestamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
486           NULL, 0x00, NULL, HFILL };
487
488 static header_field_info hfi_nfq_ifindex_indev NETLINK_NETFILTER_HFI_INIT =
489         { "IFINDEX_INDEV", "netlink-netfilter.queue.ifindex_indev", FT_UINT32, BASE_DEC,
490           NULL, 0x00, NULL, HFILL };
491
492 static header_field_info hfi_nfq_ifindex_outdev NETLINK_NETFILTER_HFI_INIT =
493         { "IFINDEX_OUTDEV", "netlink-netfilter.queue.ifindex_outdev", FT_UINT32, BASE_DEC,
494           NULL, 0x00, NULL, HFILL };
495
496 static header_field_info hfi_nfq_ifindex_physindev NETLINK_NETFILTER_HFI_INIT =
497         { "IFINDEX_PHYSINDEV", "netlink-netfilter.queue.ifindex_physindev", FT_UINT32, BASE_DEC,
498           NULL, 0x00, NULL, HFILL };
499
500 static header_field_info hfi_nfq_ifindex_physoutdev NETLINK_NETFILTER_HFI_INIT =
501         { "IFINDEX_PHYSOUTDEV", "netlink-netfilter.queue.ifindex_physoutdev", FT_UINT32, BASE_DEC,
502           NULL, 0x00, NULL, HFILL };
503
504 static header_field_info hfi_nfq_hwaddr_len NETLINK_NETFILTER_HFI_INIT =
505         { "Address length", "netlink-netfilter.queue.hwaddr.len", FT_UINT16, BASE_DEC,
506           NULL, 0x00, NULL, HFILL };
507
508 static header_field_info hfi_nfq_hwaddr_addr NETLINK_NETFILTER_HFI_INIT =
509         { "Address", "netlink-netfilter.queue.hwaddr.addr", FT_ETHER, BASE_NONE,
510           NULL, 0x00, NULL, HFILL };
511
512 static header_field_info hfi_nfq_ctinfo NETLINK_NETFILTER_HFI_INIT =
513         { "Conntrack info", "netlink-netfilter.queue.ct_info", FT_UINT32, BASE_DEC,
514           VALS(nfq_ctinfo_vals), 0x00, "Connection state tracking info", HFILL };
515
516 static header_field_info hfi_nfq_caplen NETLINK_NETFILTER_HFI_INIT =
517         { "Length of captured packet", "netlink-netfilter.queue.caplen", FT_UINT32, BASE_DEC,
518           NULL, 0x00, "Length of captured, untruncated packet", HFILL };
519
520 static header_field_info hfi_nfq_uid NETLINK_NETFILTER_HFI_INIT =
521         { "UID", "netlink-netfilter.queue.uid", FT_UINT32, BASE_DEC,
522           NULL, 0x00, NULL, HFILL };
523
524 static header_field_info hfi_nfq_gid NETLINK_NETFILTER_HFI_INIT =
525         { "GID", "netlink-netfilter.queue.gid", FT_UINT32, BASE_DEC,
526           NULL, 0x00, NULL, HFILL };
527
528 static int
529 dissect_nfq_attrs(tvbuff_t *tvb, void *data, proto_tree *tree, int nla_type, int offset, int len)
530 {
531         enum ws_nfqnl_attr_type type = (enum ws_nfqnl_attr_type) nla_type;
532         netlink_netfilter_info_t *info = (netlink_netfilter_info_t *) data;
533
534         switch (type) {
535                 case WS_NFQA_UNSPEC:
536                         break;
537
538                 case WS_NFQA_PACKET_HDR:
539                         if (len == 7) {
540                                 proto_tree_add_item(tree, &hfi_nfq_packet_id, tvb, offset, 4, ENC_BIG_ENDIAN);
541                                 offset += 4;
542
543                                 proto_tree_add_item(tree, &hfi_nfq_packet_hwprotocol, tvb, offset, 2, ENC_BIG_ENDIAN);
544                                 info->hw_protocol = tvb_get_ntohs(tvb, offset);
545                                 offset += 2;
546
547                                 proto_tree_add_item(tree, &hfi_nfq_packet_hook, tvb, offset, 1, ENC_NA);
548                                 offset++;
549                         }
550                         break;
551
552                 case WS_NFQA_VERDICT_HDR:
553                         if (len == 8) {
554                                 proto_tree_add_item(tree, &hfi_nfq_verdict_verdict, tvb, offset, 4, ENC_BIG_ENDIAN);
555                                 offset += 4;
556
557                                 proto_tree_add_item(tree, &hfi_nfq_verdict_id, tvb, offset, 4, ENC_BIG_ENDIAN);
558                                 offset += 4;
559                         }
560                         break;
561
562                 case WS_NFQA_MARK:
563                         if (len == 4) {
564                                 proto_tree_add_item(tree, &hfi_nfq_nfmark, tvb, offset, 4, ENC_BIG_ENDIAN);
565                                 offset += 4;
566                         }
567                         break;
568
569                 case WS_NFQA_TIMESTAMP:
570                         if (len == 16) {
571                                 nstime_t ts;
572
573                                 ts.secs = (time_t)tvb_get_ntoh64(tvb, offset);
574                                 ts.nsecs = (int)tvb_get_ntoh64(tvb, offset + 8) * 1000;
575                                 proto_tree_add_time(tree, &hfi_nfq_timestamp, tvb, offset, 16, &ts);
576                                 offset += 16;
577                         }
578                         break;
579
580                 case WS_NFQA_IFINDEX_INDEV:
581                         if (len == 4) {
582                                 proto_tree_add_item(tree, &hfi_nfq_ifindex_indev, tvb, offset, 4, ENC_BIG_ENDIAN);
583                                 offset += 4;
584                         }
585                         break;
586
587                 case WS_NFQA_IFINDEX_OUTDEV:
588                         if (len == 4) {
589                                 proto_tree_add_item(tree, &hfi_nfq_ifindex_outdev, tvb, offset, 4, ENC_BIG_ENDIAN);
590                                 offset += 4;
591                         }
592                         break;
593
594                 case WS_NFQA_IFINDEX_PHYSINDEV:
595                         if (len == 4) {
596                                 proto_tree_add_item(tree, &hfi_nfq_ifindex_physindev, tvb, offset, 4, ENC_BIG_ENDIAN);
597                                 offset += 4;
598                         }
599                         break;
600
601                 case WS_NFQA_IFINDEX_PHYSOUTDEV:
602                         if (len == 4) {
603                                 proto_tree_add_item(tree, &hfi_nfq_ifindex_physoutdev, tvb, offset, 4, ENC_BIG_ENDIAN);
604                                 offset += 4;
605                         }
606                         break;
607
608                 case WS_NFQA_HWADDR:
609                         if (len >= 4) {
610                                 guint16 addrlen;
611
612                                 proto_tree_add_item(tree, &hfi_nfq_hwaddr_len, tvb, offset, 2, ENC_BIG_ENDIAN);
613                                 addrlen = tvb_get_ntohs(tvb, offset);
614                                 offset += 4; /* skip len and padding */
615
616                                 /* XXX expert info if 4 + addrlen > len. */
617                                 addrlen = MIN(addrlen, len - 4);
618                                 proto_tree_add_item(tree, &hfi_nfq_hwaddr_addr, tvb, offset, addrlen, ENC_BIG_ENDIAN);
619                                 offset += addrlen;
620                         }
621                         break;
622
623                 case WS_NFQA_PAYLOAD:
624                         if (len > 0) {
625                                 tvbuff_t *next_tvb = tvb_new_subset_length(tvb, offset, len);
626                                 proto_tree *parent_tree = proto_item_get_parent(tree);
627
628                                 if (!dissector_try_uint(ethertype_table, info->hw_protocol, next_tvb, info->pinfo, parent_tree))
629                                         call_data_dissector(next_tvb, info->pinfo, parent_tree);
630                                 offset += len;
631                         }
632                         break;
633
634                 case WS_NFQA_CT:
635                         /* TODO */
636                         break;
637
638                 case WS_NFQA_CT_INFO:
639                         if (len == 4) {
640                                 proto_tree_add_item(tree, &hfi_nfq_ctinfo, tvb, offset, 4, ENC_BIG_ENDIAN);
641                                 offset += 4;
642                         }
643                         break;
644
645                 case WS_NFQA_CAP_LEN:
646                         if (len == 4) {
647                                 proto_tree_add_item(tree, &hfi_nfq_caplen, tvb, offset, 4, ENC_BIG_ENDIAN);
648                                 offset += 4;
649                         }
650                         break;
651
652                 case WS_NFQA_SKB_INFO:
653                 case WS_NFQA_EXP:
654                         /* TODO */
655                         break;
656
657                 case WS_NFQA_UID:
658                         if (len == 4) {
659                                 proto_tree_add_item(tree, &hfi_nfq_uid, tvb, offset, 4, ENC_BIG_ENDIAN);
660                                 offset += 4;
661                         }
662                         break;
663
664                 case WS_NFQA_GID:
665                         if (len == 4) {
666                                 proto_tree_add_item(tree, &hfi_nfq_gid, tvb, offset, 4, ENC_BIG_ENDIAN);
667                                 offset += 4;
668                         }
669                         break;
670
671                 case WS_NFQA_SECCTX:
672                 case WS_NFQA_VLAN:
673                 case WS_NFQA_L2HDR:
674                         /* TODO */
675                         break;
676         }
677
678         return offset;
679 }
680
681 static header_field_info hfi_nfq_attr NETLINK_NETFILTER_HFI_INIT =
682         { "Type", "netlink-netfilter.queue.attr", FT_UINT16, BASE_DEC,
683           VALS(nfq_attr_vals), NLA_TYPE_MASK, NULL, HFILL };
684
685 /* QUEUE - main */
686
687 static int
688 dissect_netfilter_queue(tvbuff_t *tvb, netlink_netfilter_info_t *info, proto_tree *tree, int offset)
689 {
690         enum ws_nfqnl_msg_types type = (enum ws_nfqnl_msg_types) (info->data->type & 0xff);
691
692         offset = dissect_netlink_netfilter_header(tvb, tree, offset);
693
694         switch (type) {
695                 case WS_NFQNL_MSG_CONFIG:
696                         return dissect_netlink_attributes(tvb, &hfi_nfq_config_attr, ett_nfq_config_attr, info, tree, offset, -1, dissect_nfq_config_attrs);
697
698                 case WS_NFQNL_MSG_PACKET:
699                 case WS_NFQNL_MSG_VERDICT:
700                         return dissect_netlink_attributes(tvb, &hfi_nfq_attr, ett_nfq_attr, info, tree, offset, -1, dissect_nfq_attrs);
701
702                 case WS_NFQNL_MSG_VERDICT_BATCH:
703                         /* TODO */
704                         break;
705         }
706
707         return offset;
708 }
709
710 /* ULOG */
711
712 static const value_string netlink_netfilter_ulog_type_vals[] = {
713         { WS_NFULNL_MSG_PACKET, "Packet" },
714         { WS_NFULNL_MSG_CONFIG, "Config" },
715         { 0, NULL }
716 };
717
718 static header_field_info hfi_netlink_netfilter_ulog_type NETLINK_NETFILTER_HFI_INIT =
719         { "Type", "netlink-netfilter.ulog_type", FT_UINT16, BASE_DEC,
720           VALS(netlink_netfilter_ulog_type_vals), 0x00FF, NULL, HFILL };
721
722 static int
723 dissect_netfilter_ulog(tvbuff_t *tvb, netlink_netfilter_info_t *info, proto_tree *tree, int offset)
724 {
725         enum ws_nfulnl_msg_types type = (enum ws_nfulnl_msg_types) (info->data->type & 0xff);
726
727         switch (type) {
728                 case WS_NFULNL_MSG_PACKET:
729                         /* Note that NFLOG dissects the nfgenmsg header */
730                         call_dissector(nflog_handle, tvb, info->pinfo, tree);
731                         break;
732
733                 default:
734                         break;
735         }
736
737         return offset;
738 }
739
740 /* IPSET */
741
742 static const value_string ipset_command_vals[] = {
743         { WS_IPSET_CMD_NONE,        "None" },
744         { WS_IPSET_CMD_PROTOCOL,    "Return protocol version" },
745         { WS_IPSET_CMD_CREATE,      "Create a new (empty) set" },
746         { WS_IPSET_CMD_DESTROY,     "Destroy a (empty) set" },
747         { WS_IPSET_CMD_FLUSH,       "Remove all elements from a set" },
748         { WS_IPSET_CMD_RENAME,      "Rename a set" },
749         { WS_IPSET_CMD_SWAP,        "Swap two sets" },
750         { WS_IPSET_CMD_LIST,        "List sets" },
751         { WS_IPSET_CMD_SAVE,        "Save sets" },
752         { WS_IPSET_CMD_ADD,         "Add an element to a set" },
753         { WS_IPSET_CMD_DEL,         "Delete an element from a set" },
754         { WS_IPSET_CMD_TEST,        "Test an element in a set" },
755         { WS_IPSET_CMD_HEADER,      "Get set header data only" },
756         { WS_IPSET_CMD_TYPE,        "Get set type" },
757         { 0, NULL }
758 };
759
760 static const value_string ipset_attr_vals[] = {
761         { WS_IPSET_ATTR_PROTOCOL,       "Protocol version" },
762         { WS_IPSET_ATTR_SETNAME,        "Name of the set" },
763         { WS_IPSET_ATTR_TYPENAME,       "Typename" },
764         { WS_IPSET_ATTR_REVISION,       "Settype revision" },
765         { WS_IPSET_ATTR_FAMILY,         "Settype family" },
766         { WS_IPSET_ATTR_FLAGS,          "Flags at command level" },
767         { WS_IPSET_ATTR_DATA,           "Nested attributes" },
768         { WS_IPSET_ATTR_ADT,            "Multiple data containers" },
769         { WS_IPSET_ATTR_LINENO,         "Restore lineno" },
770         { WS_IPSET_ATTR_PROTOCOL_MIN,   "Minimal supported version number" },
771         { 0, NULL }
772 };
773
774 static const value_string ipset_cadt_attr_vals[] = {
775         { WS_IPSET_ATTR_IP_FROM,        "IP_FROM" },
776         { WS_IPSET_ATTR_IP_TO,          "IP_TO" },
777         { WS_IPSET_ATTR_CIDR,           "CIDR" },
778         { WS_IPSET_ATTR_PORT_FROM,      "PORT_FROM" },
779         { WS_IPSET_ATTR_PORT_TO,        "PORT_TO" },
780         { WS_IPSET_ATTR_TIMEOUT,        "TIMEOUT" },
781         { WS_IPSET_ATTR_PROTO,          "PROTO" },
782         { WS_IPSET_ATTR_CADT_FLAGS,     "CADT_FLAGS" },
783         { WS_IPSET_ATTR_CADT_LINENO,    "CADT_LINENO" },
784         { WS_IPSET_ATTR_MARK,           "MARK" },
785         { WS_IPSET_ATTR_MARKMASK,       "MARKMASK" },
786         /* up to 16 is reserved. */
787         { WS_IPSET_ATTR_GC,             "GC" },
788         { WS_IPSET_ATTR_HASHSIZE,       "HASHSIZE" },
789         { WS_IPSET_ATTR_MAXELEM,        "MAXELEM" },
790         { WS_IPSET_ATTR_NETMASK,        "NETMASK" },
791         { WS_IPSET_ATTR_PROBES,         "PROBES" },
792         { WS_IPSET_ATTR_RESIZE,         "RESIZE" },
793         { WS_IPSET_ATTR_SIZE,           "SIZE" },
794         { WS_IPSET_ATTR_ELEMENTS,       "ELEMENTS" },
795         { WS_IPSET_ATTR_REFERENCES,     "REFERENCES" },
796         { WS_IPSET_ATTR_MEMSIZE,        "MEMSIZE" },
797         { 0, NULL }
798 };
799
800 static const value_string ipset_adt_attr_vals[] = {
801         /* Nasty! Duplication from CADT above... */
802         { WS_IPSET_ATTR_IP_FROM,        "IP_FROM" },
803         { WS_IPSET_ATTR_IP_TO,          "IP_TO" },
804         { WS_IPSET_ATTR_CIDR,           "CIDR" },
805         { WS_IPSET_ATTR_PORT_FROM,      "PORT_FROM" },
806         { WS_IPSET_ATTR_PORT_TO,        "PORT_TO" },
807         { WS_IPSET_ATTR_TIMEOUT,        "TIMEOUT" },
808         { WS_IPSET_ATTR_PROTO,          "PROTO" },
809         { WS_IPSET_ATTR_CADT_FLAGS,     "CADT_FLAGS" },
810         { WS_IPSET_ATTR_CADT_LINENO,    "CADT_LINENO" },
811         { WS_IPSET_ATTR_MARK,           "MARK" },
812         { WS_IPSET_ATTR_MARKMASK,       "MARKMASK" },
813         /* End of duplication, other attributes follow. */
814         { WS_IPSET_ATTR_ETHER,          "ETHER" },
815         { WS_IPSET_ATTR_NAME,           "NAME" },
816         { WS_IPSET_ATTR_NAMEREF,        "NAMEREF" },
817         { WS_IPSET_ATTR_IP2,            "IP2" },
818         { WS_IPSET_ATTR_CIDR2,          "CIDR2" },
819         { WS_IPSET_ATTR_IP2_TO,         "IP2_TO" },
820         { WS_IPSET_ATTR_IFACE,          "IFACE" },
821         { WS_IPSET_ATTR_BYTES,          "BYTES" },
822         { WS_IPSET_ATTR_PACKETS,        "PACKETS" },
823         { WS_IPSET_ATTR_COMMENT,        "COMMENT" },
824         { WS_IPSET_ATTR_SKBMARK,        "SKBMARK" },
825         { WS_IPSET_ATTR_SKBPRIO,        "SKBPRIO" },
826         { WS_IPSET_ATTR_SKBQUEUE,       "SKBQUEUE" },
827         { WS_IPSET_ATTR_PAD,            "PAD" },
828         { 0, NULL }
829 };
830
831 static const value_string ipset_ip_attr_vals[] = {
832         { WS_IPSET_ATTR_IPADDR_IPV4,    "IPv4 address" },
833         { WS_IPSET_ATTR_IPADDR_IPV6,    "IPv6 address" },
834         { 0, NULL }
835 };
836
837 static header_field_info hfi_ipset_attr NETLINK_NETFILTER_HFI_INIT =
838         { "Type", "netlink-netfilter.ipset_attr", FT_UINT16, BASE_DEC,
839           VALS(ipset_attr_vals), NLA_TYPE_MASK, NULL, HFILL };
840
841 static header_field_info hfi_ipset_cadt_attr NETLINK_NETFILTER_HFI_INIT =
842         { "Type", "netlink-netfilter.ipset_cadt_attr", FT_UINT16, BASE_DEC,
843           VALS(ipset_cadt_attr_vals), NLA_TYPE_MASK, NULL, HFILL };
844
845 static header_field_info hfi_ipset_cadt_attr_cidr NETLINK_NETFILTER_HFI_INIT =
846         { "CIDR", "netlink-netfilter.ipset.cidr", FT_UINT8, BASE_DEC,
847           NULL, 0x0, NULL, HFILL };
848
849 static header_field_info hfi_ipset_cadt_attr_timeout NETLINK_NETFILTER_HFI_INIT =
850         { "Timeout", "netlink-netfilter.ipset.timeout", FT_UINT32, BASE_DEC,
851           NULL, 0x0, NULL, HFILL };
852
853 static header_field_info hfi_ipset_cadt_attr_cadt_flags NETLINK_NETFILTER_HFI_INIT =
854         { "Flags", "netlink-netfilter.ipset.cadt_flags", FT_UINT32, BASE_HEX,
855           NULL, 0x0, NULL, HFILL };
856
857 static header_field_info hfi_ipset_attr_setname NETLINK_NETFILTER_HFI_INIT =
858         { "Setname", "netlink-netfilter.ipset.setname", FT_STRINGZ, STR_UNICODE,
859           NULL, 0x0, NULL, HFILL };
860
861 static header_field_info hfi_ipset_attr_typename NETLINK_NETFILTER_HFI_INIT =
862         { "Typename", "netlink-netfilter.ipset.typename", FT_STRINGZ, STR_UNICODE,
863           NULL, 0x0, NULL, HFILL };
864
865 static header_field_info hfi_ipset_attr_family NETLINK_NETFILTER_HFI_INIT =
866         { "Address family", "netlink-netfilter.ipset.family", FT_UINT8, BASE_DEC | BASE_EXT_STRING,
867           &linux_af_vals_ext, 0x00, NULL, HFILL };
868
869 static header_field_info hfi_ipset_attr_flags NETLINK_NETFILTER_HFI_INIT =
870         { "Flags", "netlink-netfilter.ipset.flags", FT_UINT32, BASE_HEX,
871           NULL, 0x0, NULL, HFILL };
872
873 static header_field_info hfi_ipset_adt_attr NETLINK_NETFILTER_HFI_INIT =
874         { "Type", "netlink-netfilter.ipset_adt_attr", FT_UINT16, BASE_DEC,
875           VALS(ipset_adt_attr_vals), NLA_TYPE_MASK, NULL, HFILL };
876
877 static header_field_info hfi_ipset_adt_attr_comment NETLINK_NETFILTER_HFI_INIT =
878         { "Comment", "netlink-netfilter.ipset.comment", FT_STRINGZ, STR_UNICODE,
879           NULL, 0x0, NULL, HFILL };
880
881 static header_field_info hfi_ipset_ip_attr NETLINK_NETFILTER_HFI_INIT =
882         { "Type", "netlink-netfilter.ipset_ip_attr", FT_UINT16, BASE_DEC,
883           VALS(ipset_ip_attr_vals), NLA_TYPE_MASK, NULL, HFILL };
884
885 static header_field_info hfi_ipset_ip_attr_ipv4 NETLINK_NETFILTER_HFI_INIT =
886         { "IPv4 address", "netlink-netfilter.ipset.ip_addr", FT_IPv4, BASE_NONE,
887           NULL, 0x00, NULL, HFILL };
888
889 static header_field_info hfi_ipset_ip_attr_ipv6 NETLINK_NETFILTER_HFI_INIT =
890         { "IPv6 address", "netlink-netfilter.ipset.ip6_addr", FT_IPv6, BASE_NONE,
891           NULL, 0x00, NULL, HFILL };
892
893 static int
894 dissect_ipset_ip_attrs(tvbuff_t *tvb, void *data _U_, proto_tree *tree, int nla_type, int offset, int len)
895 {
896         enum ws_ipset_ip_attr type = (enum ws_ipset_ip_attr) nla_type & NLA_TYPE_MASK;
897
898         switch (type) {
899                 case WS_IPSET_ATTR_IPADDR_IPV4:
900                         proto_tree_add_item(tree, &hfi_ipset_ip_attr_ipv4, tvb, offset, len, ENC_BIG_ENDIAN);
901                         return 1;
902
903                 case WS_IPSET_ATTR_IPADDR_IPV6:
904                         proto_tree_add_item(tree, &hfi_ipset_ip_attr_ipv6, tvb, offset, len, ENC_BIG_ENDIAN);
905                         return 1;
906         }
907
908         return 0;
909 }
910
911 static int
912 dissect_ipset_cadt_attrs(tvbuff_t *tvb, void *data, proto_tree *tree, int nla_type, int offset, int len)
913 {
914         enum ws_ipset_cadt_attr type = (enum ws_ipset_cadt_attr) nla_type & NLA_TYPE_MASK;
915         netlink_netfilter_info_t *info = (netlink_netfilter_info_t *) data;
916
917         switch (type) {
918                 case WS_IPSET_ATTR_IP_FROM:
919                 case WS_IPSET_ATTR_IP_TO:
920                         if (nla_type & NLA_F_NESTED)
921                                 return dissect_netlink_attributes(tvb, &hfi_ipset_ip_attr, ett_ipset_ip_attr, info, tree, offset, len, dissect_ipset_ip_attrs);
922                         return 0;
923
924                 case WS_IPSET_ATTR_CIDR:
925                         if (len == 1) {
926                                 proto_tree_add_item(tree, &hfi_ipset_cadt_attr_cidr, tvb, offset, len, ENC_NA);
927                                 return 1;
928                         }
929                         return 0;
930
931                 case WS_IPSET_ATTR_PORT_FROM:
932                 case WS_IPSET_ATTR_PORT_TO:
933                         /* TODO */
934                         return 0;
935
936                 case WS_IPSET_ATTR_TIMEOUT:
937                         if (len == 4) {
938                                 proto_tree_add_item(tree, &hfi_ipset_cadt_attr_timeout, tvb, offset, len, ENC_BIG_ENDIAN);
939                                 return 1;
940                         }
941                         return 0;
942
943                 case WS_IPSET_ATTR_PROTO:
944                         /* TODO */
945                         return 0;
946
947                 case WS_IPSET_ATTR_CADT_FLAGS:
948                         if (len == 4) {
949                                 proto_tree_add_item(tree, &hfi_ipset_cadt_attr_cadt_flags, tvb, offset, len, ENC_BIG_ENDIAN);
950                                 /* TODO show bits from enum ipset_cadt_flags */
951                                 return 1;
952                         }
953                         return 0;
954
955                 case WS_IPSET_ATTR_CADT_LINENO:
956                 case WS_IPSET_ATTR_MARK:
957                 case WS_IPSET_ATTR_MARKMASK:
958                 case WS_IPSET_ATTR_GC:
959                 case WS_IPSET_ATTR_HASHSIZE:
960                 case WS_IPSET_ATTR_MAXELEM:
961                 case WS_IPSET_ATTR_NETMASK:
962                 case WS_IPSET_ATTR_PROBES:
963                 case WS_IPSET_ATTR_RESIZE:
964                 case WS_IPSET_ATTR_SIZE:
965                 case WS_IPSET_ATTR_ELEMENTS:
966                 case WS_IPSET_ATTR_REFERENCES:
967                 case WS_IPSET_ATTR_MEMSIZE:
968                         /* TODO */
969                         return 0;
970         }
971
972         return 0;
973 }
974
975 static int
976 dissect_ipset_adt_data_attrs(tvbuff_t *tvb, void *data, proto_tree *tree, int nla_type, int offset, int len)
977 {
978         enum ws_ipset_adt_attr type = (enum ws_ipset_adt_attr) nla_type & NLA_TYPE_MASK;
979
980         if ((nla_type & NLA_TYPE_MASK) <= WS_IPSET_ATTR_CADT_MAX)
981                 return dissect_ipset_cadt_attrs(tvb, data, tree, nla_type, offset, len);
982
983         switch (type) {
984                 case WS_IPSET_ATTR_COMMENT:
985                         proto_tree_add_item(tree, &hfi_ipset_adt_attr_comment, tvb, offset, len, ENC_UTF_8);
986                         return 1;
987
988                 default:
989                         return 0;
990         }
991
992         return 0;
993 }
994
995 static int
996 dissect_ipset_adt_attrs(tvbuff_t *tvb, void *data, proto_tree *tree, int nla_type, int offset, int len)
997 {
998         netlink_netfilter_info_t *info = (netlink_netfilter_info_t *) data;
999
1000         if (nla_type & NLA_F_NESTED)
1001                 return dissect_netlink_attributes(tvb, &hfi_ipset_adt_attr, ett_ipset_adt_attr, info, tree, offset, len, dissect_ipset_adt_data_attrs);
1002         return 0;
1003 }
1004
1005 static int
1006 dissect_ipset_attrs(tvbuff_t *tvb, void *data, proto_tree *tree, int nla_type, int offset, int len)
1007 {
1008         enum ws_ipset_attr type = (enum ws_ipset_attr) nla_type & NLA_TYPE_MASK;
1009         netlink_netfilter_info_t *info = (netlink_netfilter_info_t *) data;
1010
1011         switch (type) {
1012                 case WS_IPSET_ATTR_PROTOCOL:
1013                         /* TODO */
1014                         return 0;
1015
1016                 case WS_IPSET_ATTR_SETNAME:
1017                         proto_tree_add_item(tree, &hfi_ipset_attr_setname, tvb, offset, len, ENC_UTF_8);
1018                         return 1;
1019
1020                 case WS_IPSET_ATTR_TYPENAME:
1021                         proto_tree_add_item(tree, &hfi_ipset_attr_typename, tvb, offset, len, ENC_UTF_8);
1022                         return 1;
1023
1024                 case WS_IPSET_ATTR_REVISION:
1025                         /* TODO */
1026                         return 0;
1027
1028                 case WS_IPSET_ATTR_FAMILY:
1029                         proto_tree_add_item(tree, &hfi_ipset_attr_family, tvb, offset, len, ENC_BIG_ENDIAN);
1030                         return 1;
1031
1032                 case WS_IPSET_ATTR_FLAGS:
1033                         if (len == 4) {
1034                                 proto_tree_add_item(tree, &hfi_ipset_attr_flags, tvb, offset, len, ENC_BIG_ENDIAN);
1035                                 /* TODO show bits from enum ipset_cmd_flags */
1036                                 return 1;
1037                         }
1038                         return 0;
1039
1040                 case WS_IPSET_ATTR_DATA:
1041                         /* See ipset lib/PROTOCOL, CADT attributes only follow for some commands */
1042                         if (nla_type & NLA_F_NESTED) {
1043                                 guint16 command = info->data->type & 0xffff;
1044
1045                                 if (command == WS_IPSET_CMD_CREATE ||
1046                                     command == WS_IPSET_CMD_LIST ||
1047                                     command == WS_IPSET_CMD_SAVE)
1048                                         return dissect_netlink_attributes(tvb, &hfi_ipset_cadt_attr, ett_ipset_cadt_attr, info, tree, offset, len, dissect_ipset_cadt_attrs);
1049                                 else
1050                                         return dissect_netlink_attributes(tvb, &hfi_ipset_adt_attr, ett_ipset_adt_attr, info, tree, offset, len, dissect_ipset_adt_data_attrs);
1051                         }
1052                         return 0;
1053
1054                 case WS_IPSET_ATTR_ADT:
1055                         /* Following this, there will be an IPSET_ATTR_DATA with regular ADT attributes, not CADT */
1056                         if (nla_type & NLA_F_NESTED)
1057                                 return dissect_netlink_attributes(tvb, &hfi_ipset_attr, ett_ipset_attr, info, tree, offset, len, dissect_ipset_adt_attrs);
1058                         return 0;
1059
1060                 case WS_IPSET_ATTR_LINENO:
1061                 case WS_IPSET_ATTR_PROTOCOL_MIN:
1062                         /* TODO */
1063                         return 0;
1064         }
1065
1066         return 0;
1067 }
1068
1069 static int
1070 dissect_netfilter_ipset(tvbuff_t *tvb, netlink_netfilter_info_t *info, proto_tree *tree, int offset)
1071 {
1072         offset = dissect_netlink_netfilter_header(tvb, tree, offset);
1073         return dissect_netlink_attributes(tvb, &hfi_ipset_attr, ett_ipset_attr, info, tree, offset, -1, dissect_ipset_attrs);
1074 }
1075
1076
1077 static const value_string netlink_netfilter_subsystem_vals[] = {
1078         { WS_NFNL_SUBSYS_NONE,              "None" },
1079         { WS_NFNL_SUBSYS_CTNETLINK,         "Conntrack" },
1080         { WS_NFNL_SUBSYS_CTNETLINK_EXP,     "Conntrack expect" },
1081         { WS_NFNL_SUBSYS_QUEUE,             "Netfilter packet queue" },
1082         { WS_NFNL_SUBSYS_ULOG,              "Netfilter userspace logging" },
1083         { WS_NFNL_SUBSYS_OSF,               "OS fingerprint" },
1084         { WS_NFNL_SUBSYS_IPSET,             "IP set" },
1085         { WS_NFNL_SUBSYS_ACCT,              "Extended Netfilter accounting infrastructure" },
1086         { WS_NFNL_SUBSYS_CTNETLINK_TIMEOUT, "Extended Netfilter Connection Tracking timeout tuning" },
1087         { WS_NFNL_SUBSYS_CTHELPER,          "Connection Tracking Helpers" },
1088         { WS_NFNL_SUBSYS_NFTABLES,          "Netfilter tables" },
1089         { WS_NFNL_SUBSYS_NFT_COMPAT,        "x_tables compatibility layer for nf_tables" },
1090         { 0, NULL }
1091 };
1092
1093 static header_field_info hfi_nfq_type NETLINK_NETFILTER_HFI_INIT =
1094         { "Type", "netlink-netfilter.queue_type", FT_UINT16, BASE_DEC,
1095           VALS(nfq_type_vals), 0x00FF, NULL, HFILL };
1096
1097 static header_field_info hfi_ipset_command NETLINK_NETFILTER_HFI_INIT =
1098         { "Command", "netlink-netfilter.ipset_command", FT_UINT16, BASE_DEC,
1099           VALS(ipset_command_vals), 0x00FF, NULL, HFILL };
1100
1101 static header_field_info hfi_netlink_netfilter_subsys NETLINK_NETFILTER_HFI_INIT =
1102         { "Subsystem", "netlink-netfilter.subsys", FT_UINT16, BASE_DEC,
1103           VALS(netlink_netfilter_subsystem_vals), 0xFF00, NULL, HFILL };
1104
1105 static int
1106 dissect_netlink_netfilter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *_data)
1107 {
1108         struct packet_netlink_data *data = NULL;
1109         netlink_netfilter_info_t info;
1110         int offset;
1111
1112         if (_data) {
1113                 if (((struct packet_netlink_data *) _data)->magic == PACKET_NETLINK_MAGIC)
1114                         data = (struct packet_netlink_data *) _data;
1115         }
1116
1117         DISSECTOR_ASSERT(data);
1118
1119         col_set_str(pinfo->cinfo, COL_PROTOCOL, "Netlink netfilter");
1120         col_clear(pinfo->cinfo, COL_INFO);
1121
1122         proto_item_set_text(tree, "Linux netlink netfilter message");
1123
1124         /* XXX, from header tvb */
1125         proto_tree_add_uint(tree, &hfi_netlink_netfilter_subsys, NULL, 0, 0, data->type);
1126         switch (data->type >> 8) {
1127                 case WS_NFNL_SUBSYS_QUEUE:
1128                         proto_tree_add_uint(tree, &hfi_nfq_type, NULL, 0, 0, data->type);
1129                         break;
1130
1131                 case WS_NFNL_SUBSYS_ULOG:
1132                         proto_tree_add_uint(tree, &hfi_netlink_netfilter_ulog_type, NULL, 0, 0, data->type);
1133                         break;
1134
1135                 case WS_NFNL_SUBSYS_IPSET:
1136                         proto_tree_add_uint(tree, &hfi_ipset_command, NULL, 0, 0, data->type);
1137                         break;
1138         }
1139
1140         info.encoding = data->encoding;
1141         info.pinfo = pinfo;
1142         info.data = data;
1143         info.hw_protocol = 0;
1144
1145         offset = 0;
1146
1147         switch (data->type >> 8) {
1148                 case WS_NFNL_SUBSYS_QUEUE:
1149                         offset = dissect_netfilter_queue(tvb, &info, tree, offset);
1150                         break;
1151
1152                 case WS_NFNL_SUBSYS_ULOG:
1153                         offset = dissect_netfilter_ulog(tvb, &info, tree, offset);
1154                         break;
1155
1156                 case WS_NFNL_SUBSYS_IPSET:
1157                         offset = dissect_netfilter_ipset(tvb, &info, tree, offset);
1158                         break;
1159         }
1160
1161         return offset;
1162 }
1163
1164 void
1165 proto_register_netlink_netfilter(void)
1166 {
1167 #ifndef HAVE_HFI_SECTION_INIT
1168         static header_field_info *hfi[] = {
1169                 &hfi_netlink_netfilter_subsys,
1170                 &hfi_netlink_netfilter_family,
1171                 &hfi_netlink_netfilter_version,
1172                 &hfi_netlink_netfilter_resid,
1173
1174         /* QUEUE */
1175                 &hfi_nfq_type,
1176                 &hfi_nfq_attr,
1177                 &hfi_nfq_config_command_command,
1178                 &hfi_nfq_config_command_pf,
1179                 &hfi_nfq_config_params_copyrange,
1180                 &hfi_nfq_config_params_copymode,
1181                 &hfi_nfq_config_queue_maxlen,
1182                 &hfi_nfq_config_mask,
1183                 &hfi_nfq_config_flags,
1184                 &hfi_nfq_config_attr,
1185                 &hfi_nfq_verdict_verdict,
1186                 &hfi_nfq_verdict_id,
1187                 &hfi_nfq_packet_id,
1188                 &hfi_nfq_packet_hwprotocol,
1189                 &hfi_nfq_packet_hook,
1190                 &hfi_nfq_nfmark,
1191                 &hfi_nfq_timestamp,
1192                 &hfi_nfq_ifindex_indev,
1193                 &hfi_nfq_ifindex_outdev,
1194                 &hfi_nfq_ifindex_physindev,
1195                 &hfi_nfq_ifindex_physoutdev,
1196                 &hfi_nfq_hwaddr_len,
1197                 &hfi_nfq_hwaddr_addr,
1198                 &hfi_nfq_ctinfo,
1199                 &hfi_nfq_caplen,
1200                 &hfi_nfq_uid,
1201                 &hfi_nfq_gid,
1202         /* ULOG */
1203                 &hfi_netlink_netfilter_ulog_type,
1204         /* IPSET */
1205                 &hfi_ipset_command,
1206                 &hfi_ipset_attr,
1207                 &hfi_ipset_cadt_attr,
1208                 &hfi_ipset_cadt_attr_cidr,
1209                 &hfi_ipset_cadt_attr_timeout,
1210                 &hfi_ipset_cadt_attr_cadt_flags,
1211                 &hfi_ipset_attr_setname,
1212                 &hfi_ipset_attr_typename,
1213                 &hfi_ipset_attr_family,
1214                 &hfi_ipset_attr_flags,
1215                 &hfi_ipset_adt_attr,
1216                 &hfi_ipset_adt_attr_comment,
1217                 &hfi_ipset_ip_attr,
1218                 &hfi_ipset_ip_attr_ipv4,
1219                 &hfi_ipset_ip_attr_ipv6,
1220         };
1221 #endif
1222
1223         static gint *ett[] = {
1224                 &ett_netlink_netfilter,
1225                 &ett_nfq_config_attr,
1226                 &ett_nfq_attr,
1227                 &ett_ipset_attr,
1228                 &ett_ipset_cadt_attr,
1229                 &ett_ipset_adt_attr,
1230                 &ett_ipset_ip_attr,
1231         };
1232
1233         int proto_netlink_netfilter;
1234
1235         proto_netlink_netfilter = proto_register_protocol("Linux netlink netfilter protocol", "netfilter", "netlink-netfilter" );
1236         hfi_netlink_netfilter = proto_registrar_get_nth(proto_netlink_netfilter);
1237
1238         proto_register_fields(proto_netlink_netfilter, hfi, array_length(hfi));
1239         proto_register_subtree_array(ett, array_length(ett));
1240
1241         netlink_netfilter = create_dissector_handle(dissect_netlink_netfilter, proto_netlink_netfilter);
1242 }
1243
1244 void
1245 proto_reg_handoff_netlink_netfilter(void)
1246 {
1247         dissector_add_uint("netlink.protocol", WS_NETLINK_NETFILTER, netlink_netfilter);
1248
1249         nflog_handle = find_dissector_add_dependency("nflog", hfi_netlink_netfilter->id);
1250         ethertype_table = find_dissector_table("ethertype");
1251 }
1252
1253 /*
1254  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1255  *
1256  * Local variables:
1257  * c-basic-offset: 8
1258  * tab-width: 8
1259  * indent-tabs-mode: t
1260  * End:
1261  *
1262  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1263  * :indentSize=8:tabSize=8:noTabs=false:
1264  */