Coverage Report

Created: 2026-08-14 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-nflog.c
Line
Count
Source
1
/* packet-nflog.c
2
 * Copyright 2011,2012 Jakub Zawadzki <darkjames-ws@darkjames.pl>
3
 *
4
 * Wireshark - Network traffic analyzer
5
 * By Gerald Combs <gerald@wireshark.org>
6
 * Copyright 1998
7
 *
8
 * SPDX-License-Identifier: GPL-2.0-or-later
9
 */
10
#include "config.h"
11
12
#include <epan/etypes.h>
13
#include <epan/packet.h>
14
#include <wiretap/wtap.h>
15
#include <wsutil/ws_roundup.h>
16
17
#include "packet-arp.h"
18
#include "packet-netlink.h"
19
20
void proto_register_nflog(void);
21
void proto_reg_handoff_nflog(void);
22
23
/* nfulnl_attr_type enum from <linux/netfilter/nfnetlink_log.h> */
24
enum ws_nfulnl_attr_type {
25
    WS_NFULA_UNSPEC,
26
    WS_NFULA_PACKET_HDR,
27
    WS_NFULA_MARK,               /* __u32 nfmark */
28
    WS_NFULA_TIMESTAMP,          /* nfulnl_msg_packet_timestamp */
29
    WS_NFULA_IFINDEX_INDEV,      /* __u32 ifindex */
30
    WS_NFULA_IFINDEX_OUTDEV,     /* __u32 ifindex */
31
    WS_NFULA_IFINDEX_PHYSINDEV,  /* __u32 ifindex */
32
    WS_NFULA_IFINDEX_PHYSOUTDEV, /* __u32 ifindex */
33
    WS_NFULA_HWADDR,             /* nfulnl_msg_packet_hw */
34
    WS_NFULA_PAYLOAD,            /* opaque data payload */
35
    WS_NFULA_PREFIX,             /* string prefix */
36
    WS_NFULA_UID,                /* user id of socket */
37
    WS_NFULA_SEQ,                /* instance-local sequence number */
38
    WS_NFULA_SEQ_GLOBAL,         /* global sequence number */
39
    WS_NFULA_GID,                /* group id of socket */
40
    WS_NFULA_HWTYPE,             /* hardware type */
41
    WS_NFULA_HWHEADER,           /* hardware header */
42
    WS_NFULA_HWLEN,              /* hardware header length */
43
    WS_NFULA_CT,                 /* nfnetlink_conntrack.h */
44
    WS_NFULA_CT_INFO,            /* enum ip_conntrack_info */
45
};
46
47
static const value_string nflog_tlv_vals[] = {
48
    { WS_NFULA_UNSPEC,             "NFULA_UNSPEC" },
49
    { WS_NFULA_PACKET_HDR,         "NFULA_PACKET_HDR" },
50
    { WS_NFULA_MARK,               "NFULA_MARK" },
51
    { WS_NFULA_TIMESTAMP,          "NFULA_TIMESTAMP" },
52
    { WS_NFULA_IFINDEX_INDEV,      "NFULA_IFINDEX_INDEV" },
53
    { WS_NFULA_IFINDEX_OUTDEV,     "NFULA_IFINDEX_OUTDEV" },
54
    { WS_NFULA_IFINDEX_PHYSINDEV,  "NFULA_IFINDEX_PHYSINDEV" },
55
    { WS_NFULA_IFINDEX_PHYSOUTDEV, "NFULA_IFINDEX_PHYSOUTDEV" },
56
    { WS_NFULA_HWADDR,             "NFULA_HWADDR" },
57
    { WS_NFULA_PAYLOAD,            "NFULA_PAYLOAD" },
58
    { WS_NFULA_PREFIX,             "NFULA_PREFIX" },
59
    { WS_NFULA_UID,                "NFULA_UID" },
60
    { WS_NFULA_SEQ,                "NFULA_SEQ" },
61
    { WS_NFULA_SEQ_GLOBAL,         "NFULA_SEQ_GLOBAL" },
62
    { WS_NFULA_GID,                "NFULA_GID" },
63
    { WS_NFULA_HWTYPE,             "NFULA_HWTYPE" },
64
    { WS_NFULA_HWHEADER,           "NFULA_HWHEADER" },
65
    { WS_NFULA_HWLEN,              "NFULA_HWLEN" },
66
    { WS_NFULA_CT,                 "NFULA_CT" },
67
    { WS_NFULA_CT_INFO,            "NFULA_CT_INFO" },
68
    { 0, NULL }
69
};
70
71
static int proto_nflog;
72
73
static int hf_nflog_tlv_ct;
74
static int hf_nflog_tlv_ct_info;
75
static int hf_nflog_family;
76
static int hf_nflog_resid;
77
static int hf_nflog_tlv;
78
static int hf_nflog_tlv_gid;
79
static int hf_nflog_tlv_hook;
80
static int hf_nflog_tlv_hw_type;
81
static int hf_nflog_tlv_hwheader_len;
82
static int hf_nflog_tlv_hwprotocol;
83
static int hf_nflog_tlv_ifindex_indev;
84
static int hf_nflog_tlv_ifindex_outdev;
85
static int hf_nflog_tlv_ifindex_physindev;
86
static int hf_nflog_tlv_ifindex_physoutdev;
87
static int hf_nflog_tlv_length;
88
static int hf_nflog_tlv_prefix;
89
static int hf_nflog_tlv_timestamp;
90
static int hf_nflog_tlv_type;
91
static int hf_nflog_tlv_uid;
92
static int hf_nflog_tlv_unknown;
93
static int hf_nflog_version;
94
95
static int ett_nflog;
96
static int ett_nflog_tlv;
97
98
static dissector_handle_t ip_handle;
99
static dissector_handle_t ip6_handle;
100
static dissector_handle_t eth_handle;
101
static dissector_table_t ethertype_table;
102
static dissector_handle_t nflog_handle;
103
104
static bool eth_ip_layout_inside = true;
105
106
static int
107
dissect_nflog(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
108
1
{
109
1
    const int start_tlv_offset = 4;
110
111
1
    proto_tree *nflog_tree = NULL;
112
1
    proto_item *ti;
113
114
1
    unsigned offset = 0;
115
116
1
    struct {
117
1
        proto_tree *parent;
118
1
        tvbuff_t   *buffer;
119
1
    } payload = {NULL, NULL}, hwheader = {NULL, NULL};
120
121
1
    int pf;
122
1
    uint16_t hw_protocol = 0;
123
124
1
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "NFLOG");
125
1
    col_clear(pinfo->cinfo, COL_INFO);
126
127
1
    pf = tvb_get_uint8(tvb, 0);
128
129
    /* Header */
130
1
    if (proto_field_is_referenced(tree, proto_nflog)) {
131
1
        ti = proto_tree_add_item(tree, proto_nflog, tvb, 0, -1, ENC_NA);
132
1
        nflog_tree = proto_item_add_subtree(ti, ett_nflog);
133
134
1
        proto_tree_add_item(nflog_tree, hf_nflog_family, tvb, offset, 1, ENC_NA);
135
1
        offset += 1;
136
137
1
        proto_tree_add_item(nflog_tree, hf_nflog_version, tvb, offset, 1, ENC_NA);
138
1
        offset += 1;
139
140
1
        proto_tree_add_item(nflog_tree, hf_nflog_resid, tvb, offset, 2, ENC_BIG_ENDIAN);
141
        /*offset += 2;*/
142
1
    }
143
144
1
    offset = start_tlv_offset;
145
    /* TLVs */
146
1
    while (tvb_reported_length_remaining(tvb, offset) >= 4) {
147
1
        uint16_t tlv_len = tvb_get_h_uint16(tvb, offset + 0);
148
1
        uint16_t tlv_type;
149
1
        uint16_t value_len;
150
151
1
        proto_tree *tlv_tree;
152
153
        /* malformed */
154
1
        if (tlv_len < 4)
155
1
            return offset;
156
157
0
        value_len = tlv_len - 4;
158
0
        tlv_type = (tvb_get_h_uint16(tvb, offset + 2) & 0x7fff);
159
160
0
        bool handled = false;
161
0
        ti = proto_tree_add_bytes_format(nflog_tree, hf_nflog_tlv,
162
0
                         tvb, offset, tlv_len, NULL,
163
0
                         "TLV Type: %s (%u), Length: %u",
164
0
                         val_to_str_const(tlv_type, nflog_tlv_vals, "Unknown"),
165
0
                         tlv_type, tlv_len);
166
0
        tlv_tree = proto_item_add_subtree(ti, ett_nflog_tlv);
167
0
        proto_tree_add_item(tlv_tree, hf_nflog_tlv_length, tvb, offset + 0, 2, ENC_HOST_ENDIAN);
168
0
        proto_tree_add_item(tlv_tree, hf_nflog_tlv_type, tvb, offset + 2, 2, ENC_HOST_ENDIAN);
169
0
        switch (tlv_type) {
170
0
            case WS_NFULA_PACKET_HDR:
171
0
                if (value_len == 4) {
172
0
                    proto_tree_add_item(tlv_tree, hf_nflog_tlv_hwprotocol,
173
0
                                tvb, offset + 4, 2, ENC_BIG_ENDIAN);
174
0
                    proto_tree_add_item(tlv_tree, hf_nflog_tlv_hook,
175
0
                                tvb, offset + 6, 1, ENC_NA);
176
0
                    hw_protocol = tvb_get_ntohs(tvb, offset + 4);
177
0
                    handled = true;
178
0
                }
179
0
                break;
180
0
            case WS_NFULA_IFINDEX_INDEV:
181
0
                if (value_len == 4) {
182
0
                    proto_tree_add_item(tlv_tree, hf_nflog_tlv_ifindex_indev, tvb, offset + 4, value_len, ENC_BIG_ENDIAN);
183
0
                    handled = true;
184
0
                }
185
0
                break;
186
0
            case WS_NFULA_IFINDEX_OUTDEV:
187
0
                if (value_len == 4) {
188
0
                    proto_tree_add_item(tlv_tree, hf_nflog_tlv_ifindex_outdev, tvb, offset + 4, value_len, ENC_BIG_ENDIAN);
189
0
                    handled = true;
190
0
                }
191
0
                break;
192
0
            case WS_NFULA_IFINDEX_PHYSINDEV:
193
0
                if (value_len == 4) {
194
0
                    proto_tree_add_item(tlv_tree, hf_nflog_tlv_ifindex_physindev, tvb, offset + 4, value_len, ENC_BIG_ENDIAN);
195
0
                    handled = true;
196
0
                }
197
0
                break;
198
0
            case WS_NFULA_IFINDEX_PHYSOUTDEV:
199
0
                if (value_len == 4) {
200
0
                    proto_tree_add_item(tlv_tree, hf_nflog_tlv_ifindex_physoutdev, tvb, offset + 4, value_len, ENC_BIG_ENDIAN);
201
0
                    handled = true;
202
0
                }
203
0
                break;
204
0
            case WS_NFULA_PAYLOAD:
205
0
                payload.buffer = tvb_new_subset_length(tvb, offset + 4, value_len);
206
0
                payload.parent = tlv_tree;
207
0
                handled = true;
208
0
                break;
209
0
            case WS_NFULA_PREFIX:
210
0
                if (value_len >= 1) {
211
0
                    proto_tree_add_item(tlv_tree, hf_nflog_tlv_prefix,
212
0
                                tvb, offset + 4, value_len, ENC_ASCII);
213
0
                    handled = true;
214
0
                }
215
0
                break;
216
0
            case WS_NFULA_UID:
217
0
                if (value_len == 4) {
218
0
                    proto_tree_add_item(tlv_tree, hf_nflog_tlv_uid,
219
0
                                tvb, offset + 4, value_len, ENC_BIG_ENDIAN);
220
0
                    handled = true;
221
0
                }
222
0
                break;
223
0
            case WS_NFULA_GID:
224
0
                if (value_len == 4) {
225
0
                    proto_tree_add_item(tlv_tree, hf_nflog_tlv_gid,
226
0
                                tvb, offset + 4, value_len, ENC_BIG_ENDIAN);
227
0
                    handled = true;
228
0
                }
229
0
                break;
230
0
            case WS_NFULA_TIMESTAMP:
231
0
                if (value_len == 16) {
232
                    /*
233
                     * 64-bit seconds and 64-bit microseconds.
234
                     *
235
                     * XXX - add an "expert info" warning if the
236
                     * microseconds are >= 10^6?
237
                     */
238
0
                    proto_tree_add_item(tlv_tree, hf_nflog_tlv_timestamp,
239
0
                                tvb, offset + 4, value_len,
240
0
                                ENC_TIME_SECS_USECS|ENC_BIG_ENDIAN);
241
0
                    handled = true;
242
0
                }
243
0
                break;
244
0
            case WS_NFULA_HWTYPE:
245
0
                if (value_len == 2) {
246
0
                    proto_tree_add_item(tlv_tree, hf_nflog_tlv_hw_type,
247
0
                                tvb, offset + 4, value_len, ENC_BIG_ENDIAN);
248
0
                    handled = true;
249
0
                }
250
0
                break;
251
0
            case WS_NFULA_HWHEADER:
252
0
                hwheader.buffer = tvb_new_subset_length(tvb, offset + 4, value_len);
253
0
                hwheader.parent = tlv_tree;
254
0
                handled = true;
255
0
                break;
256
0
            case WS_NFULA_HWLEN:
257
0
                if (value_len == 2 || value_len == 4) {
258
0
                    proto_tree_add_item(tlv_tree, hf_nflog_tlv_hwheader_len,
259
0
                                tvb, offset + 4, value_len, ENC_BIG_ENDIAN);
260
0
                    handled = true;
261
0
                }
262
0
                break;
263
0
            case WS_NFULA_CT:
264
0
                if (value_len > 0) {
265
0
                    proto_tree_add_item(tlv_tree, hf_nflog_tlv_ct,
266
0
                                tvb, offset + 4, value_len, ENC_ASCII);
267
0
                    handled = true;
268
0
                }
269
0
                break;
270
0
            case WS_NFULA_CT_INFO:
271
0
                if (value_len == 4) {
272
0
                    proto_tree_add_item(tlv_tree, hf_nflog_tlv_ct_info,
273
0
                                tvb, offset + 4, value_len, ENC_BIG_ENDIAN);
274
0
                    handled = true;
275
0
                }
276
0
                break;
277
0
        }
278
279
0
        if (!handled)
280
0
                proto_tree_add_item(tlv_tree, hf_nflog_tlv_unknown,
281
0
                                    tvb, offset + 4, value_len, ENC_NA);
282
0
        offset += WS_ROUNDUP_4(tlv_len); /* next TLV aligned to 4B */
283
0
    }
284
285
0
    if (hwheader.buffer && eth_handle) {
286
0
        proto_tree *parent = eth_ip_layout_inside ? hwheader.parent : tree;
287
        // for others it is not guaranteed to be full, just for avoiding errors
288
0
        if (hw_protocol == ETHERTYPE_IP) {
289
0
            call_dissector(eth_handle, hwheader.buffer, pinfo, parent);
290
0
        } else {
291
0
            call_data_dissector(hwheader.buffer, pinfo, parent);
292
0
        }
293
0
    }
294
295
0
    if (payload.buffer) {
296
0
        proto_tree *parent = eth_ip_layout_inside ? payload.parent : tree;
297
0
               if (hw_protocol) {
298
0
            if (!dissector_try_uint(ethertype_table, hw_protocol, payload.buffer, pinfo, parent))
299
0
                call_data_dissector(payload.buffer, pinfo, parent);
300
0
        } else {
301
0
            switch (pf) {
302
                /* Note: NFPROTO_INET is not supposed to appear here, it is mapped
303
                 * to NFPROTO_IPV4 or NFPROTO_IPV6 */
304
0
                case WS_NFPROTO_IPV4:
305
0
                    call_dissector(ip_handle, payload.buffer, pinfo, parent);
306
0
                    break;
307
0
                case WS_NFPROTO_IPV6:
308
0
                    call_dissector(ip6_handle, payload.buffer, pinfo, parent);
309
0
                    break;
310
0
                default:
311
0
                    call_data_dissector(payload.buffer, pinfo, parent);
312
0
                    break;
313
0
            }
314
0
        }
315
0
    }
316
0
    return tvb_captured_length(tvb);
317
0
}
318
319
void
320
proto_register_nflog(void)
321
16
{
322
16
    static hf_register_info hf[] = {
323
16
        { &hf_nflog_family,
324
16
            { "Family", "nflog.family",
325
16
              FT_UINT8, BASE_DEC, VALS(nfproto_family_vals), 0x00,
326
16
              NULL, HFILL }
327
16
        },
328
16
        { &hf_nflog_version,
329
16
            { "Version", "nflog.version",
330
16
              FT_UINT8, BASE_DEC, NULL, 0x00,
331
16
              NULL, HFILL }
332
16
        },
333
16
        { &hf_nflog_resid,
334
16
            { "Resource id", "nflog.res_id",
335
16
              FT_UINT16, BASE_DEC, NULL, 0x00,
336
16
              NULL, HFILL }
337
16
        },
338
16
        { &hf_nflog_tlv,
339
16
            { "TLV", "nflog.tlv",
340
16
              FT_BYTES, BASE_NONE, NULL, 0x00,
341
16
              NULL, HFILL }
342
16
        },
343
16
        { &hf_nflog_tlv_length,
344
16
            { "Length", "nflog.tlv_length",
345
16
              FT_UINT16, BASE_DEC, NULL, 0x00,
346
16
              "TLV Length", HFILL }
347
16
        },
348
16
        { &hf_nflog_tlv_type,
349
16
            { "Type", "nflog.tlv_type",
350
16
              FT_UINT16, BASE_DEC, VALS(nflog_tlv_vals), 0x7fff,
351
16
              "TLV Type", HFILL }
352
16
        },
353
16
        { &hf_nflog_tlv_hwprotocol,
354
16
            { "HW protocol", "nflog.protocol",
355
16
              FT_UINT16, BASE_HEX, VALS(etype_vals), 0x00,
356
16
              NULL, HFILL }
357
16
        },
358
16
        { &hf_nflog_tlv_hw_type,
359
16
            { "HW Type", "nflog.hwtype",
360
16
              FT_UINT16, BASE_DEC, VALS(arp_hrd_vals), 0x00,
361
16
              NULL, HFILL }
362
16
        },
363
16
        { &hf_nflog_tlv_hwheader_len,
364
16
            { "Hardware header length", "nflog.hwhdr_len",
365
16
              FT_UINT16, BASE_DEC, NULL, 0x00, NULL, HFILL }
366
16
        },
367
16
        { &hf_nflog_tlv_hook,
368
16
            { "Netfilter hook", "nflog.hook",
369
16
              FT_UINT8, BASE_DEC, VALS(netfilter_hooks_vals), 0x00,
370
16
              NULL, HFILL }
371
16
        },
372
16
        { &hf_nflog_tlv_ifindex_indev,
373
16
            { "IFINDEX_INDEV", "nflog.ifindex_indev",
374
16
              FT_UINT32, BASE_DEC, NULL, 0x00,
375
16
              NULL, HFILL }
376
16
        },
377
16
        { &hf_nflog_tlv_ifindex_outdev,
378
16
            { "IFINDEX_OUTDEV", "nflog.ifindex_outdev",
379
16
              FT_UINT32, BASE_DEC, NULL, 0x00,
380
16
              NULL, HFILL }
381
16
        },
382
16
        { &hf_nflog_tlv_ifindex_physindev,
383
16
            { "IFINDEX_PHYSINDEV", "nflog.ifindex_physindev",
384
16
              FT_UINT32, BASE_DEC, NULL, 0x00,
385
16
              NULL, HFILL }
386
16
        },
387
16
        { &hf_nflog_tlv_ifindex_physoutdev,
388
16
            { "IFINDEX_PHYSOUTDEV", "nflog.ifindex_physoutdev",
389
16
              FT_UINT32, BASE_DEC, NULL, 0x00,
390
16
              NULL, HFILL }
391
16
        },
392
16
        { &hf_nflog_tlv_prefix,
393
16
            { "Prefix", "nflog.prefix",
394
16
              FT_STRINGZ, BASE_NONE, NULL, 0x00,
395
16
              "TLV Prefix Value", HFILL }
396
16
        },
397
16
        { &hf_nflog_tlv_uid,
398
16
            { "UID", "nflog.uid",
399
16
              FT_INT32, BASE_DEC, NULL, 0x00,
400
16
              "TLV UID Value", HFILL }
401
16
        },
402
16
        { &hf_nflog_tlv_gid,
403
16
            { "GID", "nflog.gid",
404
16
              FT_INT32, BASE_DEC, NULL, 0x00,
405
16
              "TLV GID Value", HFILL }
406
16
        },
407
16
        { &hf_nflog_tlv_timestamp,
408
16
            { "Timestamp", "nflog.timestamp",
409
16
              FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00,
410
16
              "TLV Timestamp Value", HFILL }
411
16
        },
412
16
        { &hf_nflog_tlv_ct_info,
413
16
            { "CT INFO", "nflog.ctinfo",
414
16
              FT_INT32, BASE_DEC, VALS(nfq_ctinfo_vals), 0x00,
415
16
              "TLV CT INFO", HFILL }
416
16
        },
417
16
        { &hf_nflog_tlv_ct,
418
16
            { "CT", "nflog.ct",
419
16
              FT_STRINGZ, BASE_NONE, NULL, 0x00,
420
16
              "TLV CT", HFILL }
421
16
        },
422
16
        { &hf_nflog_tlv_unknown,
423
16
            { "Value", "nflog.tlv_value",
424
16
              FT_BYTES, BASE_NONE, NULL, 0x00,
425
16
              "TLV Value", HFILL }
426
16
        },
427
16
    };
428
429
16
    static int *ett[] = {
430
16
        &ett_nflog,
431
16
        &ett_nflog_tlv
432
16
    };
433
434
16
    module_t *nflog_module;
435
436
16
    proto_nflog = proto_register_protocol("Linux Netfilter NFLOG", "NFLOG", "nflog");
437
16
    nflog_handle = register_dissector("nflog", dissect_nflog, proto_nflog);
438
16
    proto_register_field_array(proto_nflog, hf, array_length(hf));
439
16
    proto_register_subtree_array(ett, array_length(ett));
440
    // user preferences
441
16
    nflog_module = prefs_register_protocol(proto_nflog, NULL);
442
16
    prefs_register_bool_preference(nflog_module, "eth_ip_layout_inside",
443
16
        "Place ip and eth inside",
444
16
        "Place ip and eth sections inside appropriate TLV's "
445
16
        "(payload and hw header respectively). If false, then place on top level",
446
16
        &eth_ip_layout_inside);
447
16
}
448
449
void
450
proto_reg_handoff_nflog(void)
451
16
{
452
16
    ip_handle  = find_dissector_add_dependency("ip", proto_nflog);
453
16
    ip6_handle = find_dissector_add_dependency("ipv6", proto_nflog);
454
16
    eth_handle = find_dissector_add_dependency("eth_header", proto_nflog);
455
456
16
    dissector_add_uint("wtap_encap", WTAP_ENCAP_NFLOG, nflog_handle);
457
16
    ethertype_table = find_dissector_table("ethertype");
458
16
}
459
460
/*
461
 * Editor modelines
462
 *
463
 * Local Variables:
464
 * c-basic-offset: 4
465
 * tab-width: 8
466
 * indent-tabs-mode: nil
467
 * End:
468
 *
469
 * ex: set shiftwidth=4 tabstop=8 expandtab:
470
 * :indentSize=4:tabSize=8:noTabs=true:
471
 */