Coverage Report

Created: 2026-11-12 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-isis-clv.c
Line
Count
Source
1
/* packet-isis-clv.c
2
 * Common CLV decode routines.
3
 *
4
 * Stuart Stanley <stuarts@mxmail.net>
5
 *
6
 * Wireshark - Network traffic analyzer
7
 * By Gerald Combs <gerald@wireshark.org>
8
 * Copyright 1998 Gerald Combs
9
 *
10
 * SPDX-License-Identifier: GPL-2.0-or-later
11
 */
12
13
#include "config.h"
14
15
#include <epan/packet.h>
16
#include <epan/expert.h>
17
#include "packet-isis.h"
18
#include "packet-isis-clv.h"
19
#include "packet-osi.h"
20
21
static const value_string algorithm_vals[] = {
22
    { 16, "hmac-md5" },
23
    { 20, "hmac-sha1" },
24
    { 28, "hmac-sha224" },
25
    { 32, "hmac-sha256" },
26
    { 48, "hmac-sha384" },
27
    { 64, "hmac-sha512" },
28
    { 0,  NULL }
29
};
30
31
static const value_string mt_id_vals[] = {
32
    { 0, "IPv4 Unicast" },
33
    { 1, "IPv4 In-Band Management" },
34
    { 2, "IPv6 Unicast" },
35
    { 3, "IPv4 Multicast" },
36
    { 4, "IPv6 Multicast" },
37
    { 5, "IPv6 In-Band Management" },
38
    { 4095, "Development, Experimental or Proprietary" },
39
    { 0,  NULL }
40
};
41
42
/*
43
 * Name: isis_dissect_area_address_clv()
44
 *
45
 * Description:
46
 *    Take an area address CLV and display it pieces.  An area address
47
 *    CLV is n, x byte hex strings.
48
 *
49
 * Input:
50
 *    tvbuff_t * : tvbuffer for packet data
51
 *    proto_tree * : protocol display tree to fill out.  May be NULL
52
 *    int : offset into packet data where we are.
53
 *    int : length of clv we are decoding
54
 *
55
 * Output:
56
 *    void, but we will add to proto tree if !NULL.
57
 */
58
void
59
isis_dissect_area_address_clv(proto_tree *tree, packet_info* pinfo, tvbuff_t *tvb,
60
        expert_field* expert, int hf_area, int offset, int length)
61
814
{
62
814
    int        arealen,area_idx;
63
64
1.65k
    while ( length > 0 ) {
65
1.52k
        arealen = tvb_get_uint8(tvb, offset);
66
1.52k
        length--;
67
1.52k
        if (length<=0) {
68
551
            proto_tree_add_expert_format_remaining(tree, pinfo, expert, tvb, offset,
69
551
                "short address (no length for payload)");
70
551
            return;
71
551
        }
72
969
        if ( arealen > length) {
73
129
            proto_tree_add_expert_format_remaining(tree, pinfo, expert, tvb, offset,
74
129
                "short address, packet says %d, we have %d left",
75
129
                arealen, length );
76
129
            return;
77
129
        }
78
79
840
        if ( tree ) {
80
836
            proto_item *ti;
81
82
836
            ti = proto_tree_add_bytes_format( tree, hf_area, tvb, offset, arealen + 1,
83
836
                NULL, "Area address (%d): ", arealen );
84
85
            /*
86
             * Lets turn the area address into "standard"
87
             * xx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx format string.
88
             * this is a private routine as the print_nsap_net in
89
             * epan/osi_utils.c is incomplete and we need only
90
             * a subset - actually some nice placing of dots ....
91
             */
92
4.63k
            for (area_idx = 0; area_idx < arealen; area_idx++) {
93
3.80k
                proto_item_append_text(ti, "%02x",
94
3.80k
                    tvb_get_uint8(tvb, offset+area_idx+1));
95
3.80k
                if (((area_idx & 1) == 0) &&
96
2.01k
                    (area_idx + 1 < arealen)) {
97
1.78k
                    proto_item_append_text(ti, ".");
98
1.78k
                }
99
3.80k
            }
100
836
        }
101
840
        offset += arealen + 1;
102
840
        length -= arealen;    /* length already adjusted for len fld*/
103
840
    }
104
814
}
105
106
/*
107
 * Name: isis_dissect_instance_identifier_clv()
108
 *
109
 *
110
 * Input:
111
 *    tvbuff_t * : tvbuffer for packet data
112
 *    proto_tree * : protocol display tree to fill out.  May be NULL
113
 *    int : offset into packet data where we are.
114
 *    int : length of clv we are decoding
115
 *
116
 * Output:
117
 *    void, but we will add to proto tree if !NULL.
118
 */
119
void
120
isis_dissect_instance_identifier_clv(proto_tree *tree, packet_info* pinfo, tvbuff_t *tvb,
121
        expert_field* expert, int hf_iid, int hf_supported_itid, int offset, int length)
122
195
{
123
124
195
    length--;
125
195
    if (length<=0) {
126
29
        proto_tree_add_expert_format_remaining(tree, pinfo, expert, tvb, offset,
127
29
            "short address (no length for payload)");
128
29
        return;
129
29
    }
130
131
166
    proto_tree_add_item(tree, hf_iid, tvb, offset, 2, ENC_BIG_ENDIAN);
132
166
    offset += 2;
133
166
    length -= 2;
134
135
943
    while ( length > 0 ) {
136
137
777
        proto_tree_add_item(tree, hf_supported_itid, tvb, offset, 2, ENC_BIG_ENDIAN);
138
777
        offset += 2;
139
777
        length -= 2;
140
141
777
    }
142
166
}
143
144
/*
145
 * Name: isis_dissect_authentication_clv()
146
 *
147
 * Description:
148
 *    Take apart the CLV that hold authentication information.  This
149
 *    is currently 1 octet auth type.
150
 *      the two defined authentication types
151
 *      are 1 for a clear text password,
152
 *           54 for a HMAC-MD5 digest and
153
 *           3 for CRYPTO_AUTH (rfc5310)
154
 *
155
 * Input:
156
 *    tvbuff_t * : tvbuffer for packet data
157
 *    proto_tree * : protocol display tree to fill out.  May be NULL
158
 *    int : offset into packet data where we are.
159
 *    int : length of clv we are decoding
160
 *
161
 * Output:
162
 *    void, but we will add to proto tree if !NULL.
163
 */
164
void
165
isis_dissect_authentication_clv(proto_tree *tree, packet_info* pinfo, tvbuff_t *tvb,
166
        int hf_auth_bytes, int hf_key_id, expert_field* auth_expert, int offset, int length)
167
180
{
168
180
    unsigned char pw_type;
169
180
    int auth_unsupported;
170
180
    const char *algorithm = NULL;
171
172
180
    if ( length <= 0 ) {
173
33
        return;
174
33
    }
175
176
147
    pw_type = tvb_get_uint8(tvb, offset);
177
147
    offset += 1;
178
147
    length--;
179
147
    auth_unsupported = false;
180
181
147
    switch (pw_type) {
182
3
    case 1:
183
3
        if ( length > 0 ) {
184
3
            proto_tree_add_bytes_format( tree, hf_auth_bytes, tvb, offset, length,
185
3
                NULL, "clear text (1), password (length %d) = %s", length, tvb_format_text(pinfo->pool, tvb, offset, length));
186
3
        } else {
187
0
            proto_tree_add_bytes_format( tree, hf_auth_bytes, tvb, offset, length,
188
0
                NULL, "clear text (1), no clear-text password found!!!");
189
0
        }
190
3
        break;
191
4
    case 54:
192
4
        if ( length == 16 ) {
193
0
            proto_tree_add_bytes_format( tree, hf_auth_bytes, tvb, offset, length,
194
0
                NULL, "hmac-md5 (54), message digest (length %d) = %s", length, tvb_bytes_to_str(pinfo->pool, tvb, offset, length));
195
4
        } else {
196
4
            proto_tree_add_bytes_format( tree, hf_auth_bytes, tvb, offset, length,
197
4
                NULL, "hmac-md5 (54), illegal hmac-md5 digest format (must be 16 bytes)");
198
4
        }
199
4
        break;
200
4
    case 3:
201
4
        if ( length < 2 ) {
202
0
            proto_tree_add_expert_format(tree, pinfo, auth_expert, tvb, offset, length,
203
0
                "CRYPTO_AUTH (3), too short for Key ID (%d vs 2)", length);
204
0
            break;
205
0
        }
206
4
        proto_tree_add_item(tree, hf_key_id, tvb, offset, 2, ENC_BIG_ENDIAN);
207
4
        offset += 2;
208
4
        length -= 2;
209
4
        algorithm = try_val_to_str(length, algorithm_vals);
210
4
        if ( algorithm ) {
211
0
            proto_tree_add_bytes_format( tree, hf_auth_bytes, tvb, offset, length,
212
0
                NULL, "CRYPTO_AUTH %s (3), message digest (length %d) = %s", algorithm,
213
0
                length, tvb_bytes_to_str(pinfo->pool, tvb, offset, length));
214
4
        } else {
215
4
            proto_tree_add_bytes_format( tree, hf_auth_bytes, tvb, offset, length,
216
4
                NULL, "CRYPTO_AUTH (3) illegal message digest format");
217
4
        }
218
4
        break;
219
136
    default:
220
136
        proto_tree_add_bytes_format( tree, hf_auth_bytes, tvb, offset, length,
221
136
                NULL, "type 0x%02x (0x%02x)", pw_type, length);
222
136
        auth_unsupported=true;
223
136
        break;
224
147
    }
225
226
142
    if ( auth_unsupported ) {
227
133
        proto_tree_add_expert_remaining(tree, pinfo, auth_expert, tvb, offset);
228
133
    }
229
142
}
230
231
/*
232
 * Name: isis_dissect_hostname_clv()
233
 *
234
 * Description:
235
 *      dump the hostname information found in TLV 137
236
 *      pls note that the hostname is not null terminated
237
 *
238
 * Input:
239
 *      tvbuff_t * : tvbuffer for packet data
240
 *      proto_tree * : protocol display tree to fill out.  May be NULL
241
 *      int : offset into packet data where we are.
242
 *      int : length of clv we are decoding
243
 *      int : tree id to use for proto tree.
244
 *
245
 * Output:
246
 *      void, but we will add to proto tree if !NULL.
247
 */
248
249
250
void
251
isis_dissect_hostname_clv(tvbuff_t *tvb, proto_tree *tree, int offset,
252
    int length, int tree_id)
253
28
{
254
28
    proto_item* ti = proto_tree_add_item( tree, tree_id, tvb, offset, length, ENC_ASCII|ENC_NA);
255
28
    if ( length == 0 ) {
256
9
        proto_item_append_text(ti, "--none--" );
257
9
    }
258
28
}
259
260
261
262
263
void
264
isis_dissect_mt_clv(tvbuff_t *tvb, packet_info* pinfo, proto_tree *tree, int offset, int length,
265
    int tree_id, expert_field* mtid_expert)
266
18
{
267
18
    uint16_t mt_block;
268
18
    const char *mt_desc;
269
270
760
    while (length>0) {
271
        /* length can only be a multiple of 2, otherwise there is
272
           something broken -> so decode down until length is 1 */
273
748
        if (length!=1) {
274
        /* fetch two bytes */
275
742
        mt_block=tvb_get_ntohs(tvb, offset);
276
277
742
        mt_desc = val_to_str_const(mt_block&0x0fff, mt_id_vals, "Unknown");
278
742
        proto_tree_add_uint_format ( tree, tree_id, tvb, offset, 2,
279
742
            mt_block,
280
742
            "%s Topology (0x%03x)%s%s",
281
742
                      mt_desc,
282
742
                      mt_block&0xfff,
283
742
                      (mt_block&0x8000) ? ", Overload bit set" : "",
284
742
                      (mt_block&0x4000) ? ", ATT bit set" : "" );
285
742
        } else {
286
6
        proto_tree_add_expert( tree, pinfo, mtid_expert, tvb, offset, 1);
287
6
        break;
288
6
        }
289
742
        length -= 2;
290
742
        offset += 2;
291
742
    }
292
18
}
293
294
295
/*
296
 * Name: isis_dissect_ip_int_clv()
297
 *
298
 * Description:
299
 *    Take apart the CLV that lists all the IP interfaces.  The
300
 *    meaning of which is slightly different for the different base packet
301
 *    types, but the display is not different.  What we have is n ip
302
 *    addresses, plain and simple.
303
 *
304
 * Input:
305
 *    tvbuff_t * : tvbuffer for packet data
306
 *    proto_tree * : protocol display tree to fill out.  May be NULL
307
 *    int : offset into packet data where we are.
308
 *    int : length of clv we are decoding
309
 *    int : tree id to use for proto tree.
310
 *
311
 * Output:
312
 *    void, but we will add to proto tree if !NULL.
313
 */
314
void
315
isis_dissect_ip_int_clv(proto_tree *tree, packet_info* pinfo, tvbuff_t *tvb, expert_field* expert,
316
    int offset, int length, int tree_id)
317
60
{
318
60
    if ( length <= 0 ) {
319
4
        return;
320
4
    }
321
322
1.29k
    while ( length > 0 ) {
323
1.26k
        if ( length < 4 ) {
324
17
            proto_tree_add_expert_format_remaining(tree, pinfo, expert, tvb, offset,
325
17
                "Short IP interface address (%d vs 4)",length );
326
17
            return;
327
17
        }
328
329
1.24k
        if ( tree ) {
330
1.24k
            proto_tree_add_item(tree, tree_id, tvb, offset, 4, ENC_BIG_ENDIAN);
331
1.24k
        }
332
1.24k
        offset += 4;
333
1.24k
        length -= 4;
334
1.24k
    }
335
56
}
336
337
/*
338
 * Name: isis_dissect_ipv6_int_clv()
339
 *
340
 * Description:
341
 *    Take apart the CLV that lists all the IPv6 interfaces.  The
342
 *    meaning of which is slightly different for the different base packet
343
 *    types, but the display is not different.  What we have is n ip
344
 *    addresses, plain and simple.
345
 *
346
 * Input:
347
 *    tvbuff_t * : tvbuffer for packet data
348
 *    proto_tree * : protocol display tree to fill out.  May be NULL
349
 *    int : offset into packet data where we are.
350
 *    int : length of clv we are decoding
351
 *    int : tree id to use for proto tree.
352
 *
353
 * Output:
354
 *    void, but we will add to proto tree if !NULL.
355
 */
356
void
357
isis_dissect_ipv6_int_clv(proto_tree *tree, packet_info* pinfo, tvbuff_t *tvb, expert_field* expert,
358
    int offset, int length, int tree_id)
359
46
{
360
46
    ws_in6_addr addr;
361
362
46
    if ( length <= 0 ) {
363
12
        return;
364
12
    }
365
366
267
    while ( length > 0 ) {
367
256
        if ( length < 16 ) {
368
23
            proto_tree_add_expert_format_remaining(tree, pinfo, expert, tvb, offset,
369
23
                "Short IPv6 interface address (%d vs 16)",length );
370
23
            return;
371
23
        }
372
233
        tvb_get_ipv6(tvb, offset, &addr);
373
233
        if ( tree ) {
374
227
            proto_tree_add_ipv6(tree, tree_id, tvb, offset, 16, &addr);
375
227
        }
376
233
        offset += 16;
377
233
        length -= 16;
378
233
    }
379
34
}
380
381
382
/*
383
 * Name: isis_dissect_te_router_id_clv()
384
 *
385
 * Description:
386
 *      Display the Traffic Engineering Router ID TLV #134.
387
 *      This TLV is like the IP Interface TLV, except that
388
 *      only _one_ IP address is present
389
 *
390
 * Input:
391
 *      tvbuff_t * : tvbuffer for packet data
392
 *      proto_tree * : protocol display tree to fill out.  May be NULL
393
 *      int : offset into packet data where we are.
394
 *      int : length of clv we are decoding
395
 *      int : tree id to use for proto tree.
396
 *
397
 * Output:
398
 *      void, but we will add to proto tree if !NULL.
399
 */
400
void
401
isis_dissect_te_router_id_clv(proto_tree *tree, packet_info* pinfo, tvbuff_t *tvb, expert_field* expert,
402
    int offset, int length, int tree_id)
403
29
{
404
29
    if ( length <= 0 ) {
405
3
        return;
406
3
    }
407
408
26
    if ( length != 4 ) {
409
26
        proto_tree_add_expert_format_remaining(tree, pinfo, expert, tvb, offset,
410
26
            "malformed Traffic Engineering Router ID (%d vs 4)",length );
411
26
        return;
412
26
    }
413
414
0
    proto_tree_add_item(tree, tree_id, tvb, offset, 4, ENC_BIG_ENDIAN);
415
0
}
416
417
/*
418
 * Name: isis_dissect_nlpid_clv()
419
 *
420
 * Description:
421
 *    Take apart a NLPID packet and display it.  The NLPID (for integrated
422
 *    ISIS, contains n network layer protocol IDs that the box supports.
423
 *    We max out at 256 entries.
424
 *
425
 * Input:
426
 *    tvbuff_t * : tvbuffer for packet data
427
 *    proto_tree * : protocol display tree to fill out.  May be NULL
428
 *    int : offset into packet data where we are.
429
 *    int : length of clv we are decoding
430
 *
431
 * Output:
432
 *    void, but we will add to proto tree if !NULL.
433
 */
434
435
52
#define PLURALIZE(n)  (((n) > 1) ? "s" : "")
436
437
void
438
isis_dissect_nlpid_clv(tvbuff_t *tvb, proto_tree *tree, int ett_nlpid, int hf_nlpid, int offset, int length)
439
65
{
440
65
    proto_tree *nlpid_tree;
441
65
    proto_item *ti;
442
65
    uint8_t nlpid;
443
444
65
    if (length <= 0) {
445
13
        proto_tree_add_subtree_format(tree, tvb, offset, 0, ett_nlpid, NULL, "No NLPIDs");
446
52
    } else {
447
52
        nlpid_tree = proto_tree_add_subtree_format(tree, tvb, offset, length, ett_nlpid, &ti, "NLPID%s: ", PLURALIZE(length));
448
4.88k
        while (length-- > 0 ) {
449
4.82k
            nlpid = tvb_get_uint8(tvb, offset);
450
4.82k
            proto_item_append_text(ti, "%s (0x%02x)",
451
                   /* NLPID_IEEE_8021AQ conflicts with NLPID_SNDCF. In this context, we want the former. */
452
4.82k
                   (nlpid == NLPID_IEEE_8021AQ ? "IEEE 802.1aq (SPB)" : val_to_str_const(nlpid, nlpid_vals, "Unknown")),
453
4.82k
                   nlpid);
454
4.82k
            if (length) {
455
4.77k
                proto_item_append_text(ti, ", ");
456
4.77k
            }
457
4.82k
            proto_tree_add_uint(nlpid_tree, hf_nlpid, tvb, offset, 1, nlpid);
458
4.82k
            offset++;
459
4.82k
        }
460
52
    }
461
65
}
462
463
/*
464
 * Name: isis_dissect_clvs()
465
 *
466
 * Description:
467
 *    Dispatch routine to shred all the CLVs in a packet.  We just
468
 *    walk through the clv entries in the packet.  For each one, we
469
 *    search the passed in valid clv's for this protocol (opts) for
470
 *    a matching code.  If found, we add to the display tree and
471
 *    then call the dissector.  If it is not, we just post an
472
 *    "unknown" clv entry using the passed in unknown clv tree id.
473
 *
474
 * Input:
475
 *    tvbuff_t * : tvbuffer for packet data
476
 *    packet_info * : packet_info for dissection
477
 *    proto_tree * : protocol display tree to fill out.  May be NULL
478
 *    int : offset into packet data where we are.
479
 *    isis_clv_handle_t * : NULL dissector terminated array of codes
480
 *        and handlers (along with tree text and tree id's).
481
 *    expert_field * : expert info for short length
482
 *    isis_data_t * : data about the PDU from earlier headers
483
 *    int : unknown clv tree id
484
 *
485
 * Output:
486
 *    void, but we will add to proto tree if !NULL.
487
 */
488
void
489
isis_dissect_clvs(tvbuff_t *tvb, packet_info* pinfo, proto_tree *tree, int offset,
490
    const isis_clv_handle_t *opts, expert_field *expert_short_len, isis_data_t *isis,
491
    int unknown_tree_id _U_, int tree_type, int tree_length, expert_field *ei_unknown)
492
933
{
493
933
    unsigned len = isis->pdu_length - isis->header_length; /* length of CLV area */
494
933
    uint8_t code;
495
933
    uint8_t length;
496
933
    int q;
497
933
    proto_tree    *clv_tree;
498
499
14.9k
    while ( len != 0 ) {
500
14.0k
        code = tvb_get_uint8(tvb, offset);
501
14.0k
        offset += 1;
502
14.0k
        len -= 1;
503
14.0k
        if (len == 0)
504
1
            break;
505
506
14.0k
        length = tvb_get_uint8(tvb, offset);
507
14.0k
        offset += 1;
508
14.0k
        len -= 1;
509
14.0k
        if (len == 0)
510
1
            break;
511
512
14.0k
        if ( len < length ) {
513
22
            proto_tree_add_expert_format_remaining(tree, pinfo, expert_short_len, tvb, offset,
514
22
                "Short CLV header (%d vs %d)",
515
22
                length, len );
516
22
            return;
517
22
        }
518
14.0k
        q = 0;
519
312k
        while ((opts[q].dissect != NULL )&&( opts[q].optcode != code )){
520
298k
            q++;
521
298k
        }
522
14.0k
        if ( opts[q].dissect ) {
523
            /* adjust by 2 for code/len octets */
524
4.86k
            clv_tree = proto_tree_add_subtree_format(tree, tvb, offset - 2,
525
4.86k
                    length + 2, *opts[q].tree_id, NULL, "%s (t=%u, l=%u)",
526
4.86k
                    opts[q].tree_text, opts[q].optcode, length);
527
528
4.86k
            proto_tree_add_item(clv_tree, tree_type, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
529
4.86k
            proto_tree_add_item(clv_tree, tree_length, tvb, offset - 1, 1, ENC_BIG_ENDIAN);
530
4.86k
            opts[q].dissect(tvb, pinfo, clv_tree, offset, isis, length);
531
9.15k
        } else {
532
9.15k
            clv_tree = proto_tree_add_subtree_format(tree, tvb, offset - 2,
533
9.15k
                    length + 2, unknown_tree_id, NULL, "Unknown code (t=%u, l=%u)",
534
9.15k
                    code, length);
535
9.15k
            proto_tree_add_item(clv_tree, tree_type, tvb, offset - 2, 1, ENC_BIG_ENDIAN);
536
9.15k
            proto_tree_add_item(clv_tree, tree_length, tvb, offset - 1, 1, ENC_BIG_ENDIAN);
537
9.15k
            proto_tree_add_expert_format(clv_tree, pinfo, ei_unknown, tvb, offset, length, "Dissector for IS-IS CLV (%d)"
538
9.15k
              " code not implemented, Contact Wireshark developers if you want this supported", code);
539
9.15k
        }
540
14.0k
        offset += length;
541
14.0k
        len -= length;
542
14.0k
    }
543
933
}
544
545
/*
546
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
547
 *
548
 * Local variables:
549
 * c-basic-offset: 4
550
 * tab-width: 8
551
 * indent-tabs-mode: nil
552
 * End:
553
 *
554
 * vi: set shiftwidth=4 tabstop=8 expandtab:
555
 * :indentSize=4:tabSize=8:noTabs=true:
556
 */