Coverage Report

Created: 2025-08-04 07:15

/src/wireshark/epan/dissectors/packet-teredo.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-teredo.c  v.1.0
2
 * Routines for Teredo packets disassembly
3
 *   draft-huitema-v6ops-teredo-02.txt
4
 *
5
 * Copyright 2003, Ragi BEJJANI - 6WIND - <ragi.bejjani@6wind.com>
6
 * Copyright 2003, Vincent JARDIN - 6WIND - <vincent.jardin@6wind.com>
7
 * Copyright 2004, Remi DENIS-COURMONT
8
 *
9
 * Wireshark - Network traffic analyzer
10
 * By Gerald Combs <gerald@wireshark.org>
11
 * Copyright 1998 Gerald Combs
12
 *
13
 * SPDX-License-Identifier: GPL-2.0-or-later
14
 */
15
16
#include "config.h"
17
18
#include <epan/packet.h>
19
#include <epan/prefs.h>
20
21
#include <epan/tap.h>
22
23
14
#define UDP_PORT_TEREDO 3544
24
25
void proto_reg_handoff_teredo(void);
26
void proto_register_teredo(void);
27
28
static int teredo_tap;
29
30
static int proto_teredo;
31
32
static int hf_teredo_auth;
33
static int hf_teredo_auth_idlen;
34
static int hf_teredo_auth_aulen;
35
static int hf_teredo_auth_id;
36
static int hf_teredo_auth_value;
37
static int hf_teredo_auth_nonce;
38
static int hf_teredo_auth_conf;
39
static int hf_teredo_orig;
40
static int hf_teredo_orig_port;
41
static int hf_teredo_orig_addr;
42
43
static int ett_teredo;
44
static int ett_teredo_auth;
45
static int ett_teredo_orig;
46
47
typedef struct {
48
  uint16_t th_indtyp;
49
  uint8_t th_cidlen;
50
  uint8_t th_authdlen;
51
  uint8_t th_nonce[8];
52
  uint8_t th_conf;
53
54
  uint8_t th_ip_v_hl;
55
  uint16_t th_header;
56
  uint16_t th_orgport;
57
  uint32_t th_iporgaddr;
58
} e_teredohdr;
59
60
static dissector_table_t teredo_dissector_table;
61
/*static heur_dissector_list_t heur_subdissector_list;*/
62
static dissector_handle_t teredo_handle;
63
static dissector_handle_t data_handle;
64
65
static int
66
parse_teredo_auth(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
67
      int offset, e_teredohdr *teredoh)
68
5
{
69
5
  unsigned idlen, aulen;
70
71
5
  col_append_sep_str (pinfo->cinfo, COL_INFO, ", ",
72
5
          "Authentication header");
73
74
5
  teredoh->th_indtyp = 1;
75
5
  offset += 2;
76
77
5
  idlen = tvb_get_uint8(tvb, offset);
78
5
  teredoh->th_cidlen = idlen;
79
5
  offset++;
80
81
5
  aulen = tvb_get_uint8(tvb, offset);
82
5
  teredoh->th_authdlen = aulen;
83
5
  offset++;
84
85
5
  if (tree) {
86
5
    proto_item *ti;
87
88
5
    ti = proto_tree_add_item(tree, hf_teredo_auth, tvb, offset-4,
89
5
            13 + idlen + aulen, ENC_NA);
90
5
    tree = proto_item_add_subtree(ti, ett_teredo_auth);
91
92
5
    proto_tree_add_item(tree, hf_teredo_auth_idlen, tvb,
93
5
          offset - 2, 1, ENC_BIG_ENDIAN);
94
5
    proto_tree_add_item(tree, hf_teredo_auth_aulen, tvb,
95
5
          offset - 1, 1, ENC_BIG_ENDIAN);
96
97
    /* idlen is usually zero */
98
5
    if (idlen) {
99
2
      proto_tree_add_item(tree, hf_teredo_auth_id, tvb,
100
2
            offset, idlen, ENC_NA);
101
2
      offset += idlen;
102
2
    }
103
104
    /* aulen is usually zero */
105
5
    if (aulen) {
106
3
      proto_tree_add_item(tree, hf_teredo_auth_value, tvb,
107
3
            offset, aulen, ENC_NA);
108
3
      offset += aulen;
109
3
    }
110
111
5
    proto_tree_add_item(tree, hf_teredo_auth_nonce, tvb,
112
5
          offset, 8, ENC_NA);
113
5
    offset += 8;
114
115
5
    proto_tree_add_item(tree, hf_teredo_auth_conf, tvb,
116
5
          offset, 1, ENC_NA);
117
5
    offset++;
118
5
  }
119
0
  else
120
0
    offset += idlen + aulen + 9;
121
122
5
  tvb_memcpy(tvb, teredoh->th_nonce, offset - 9, 8);
123
5
  teredoh->th_conf = tvb_get_uint8(tvb, offset - 1);
124
125
5
  return offset;
126
5
}
127
128
129
static int
130
parse_teredo_orig(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
131
      int offset, e_teredohdr *teredoh)
132
5
{
133
5
  proto_item *ti = NULL;
134
135
5
  col_append_sep_str (pinfo->cinfo, COL_INFO, ", ",
136
5
          "Origin indication");
137
138
5
  if (tree) {
139
5
    ti = proto_tree_add_item(tree, hf_teredo_orig, tvb, offset,
140
5
            8, ENC_NA);
141
5
    tree = proto_item_add_subtree(ti, ett_teredo_orig);
142
5
  }
143
5
  offset += 2;
144
145
5
  teredoh->th_orgport = tvb_get_ntohs(tvb, offset);
146
5
  if (tree) {
147
    /*
148
     * The "usual arithmetic conversions" will convert
149
     * "teredoh->th_orgport" to an "int" (because all
150
     * "unsigned short" values will fit in an "int"),
151
     * which will zero-extend it.  This means that
152
     * complementing it will turn all the zeroes in
153
     * the upper 16 bits into ones; we just want the
154
     * lower 16 bits (containing the port number)
155
     * complemented, with the result zero-extended.
156
     *
157
     * That's what the cast is for.
158
     */
159
5
    proto_tree_add_uint(tree, hf_teredo_orig_port, tvb,
160
5
          offset, 2,
161
5
          (uint16_t)~teredoh->th_orgport);
162
5
  }
163
5
  offset += 2;
164
165
5
  teredoh->th_iporgaddr = tvb_get_ipv4(tvb, offset);
166
5
  if (tree) {
167
5
    proto_tree_add_ipv4(tree, hf_teredo_orig_addr, tvb,
168
5
          offset, 4, ~teredoh->th_iporgaddr);
169
5
  }
170
5
  offset += 4;
171
172
5
  return offset;
173
5
}
174
175
176
/* Determine if there is a sub-dissector and call it.  This has been */
177
/* separated into a stand alone routine to other protocol dissectors */
178
/* can call to it, ie. socks  */
179
180
181
static void
182
decode_teredo_ports(tvbuff_t *tvb, int offset, packet_info *pinfo,proto_tree *tree, int th_header)
183
722
{
184
722
  tvbuff_t *next_tvb;
185
186
722
  next_tvb = tvb_new_subset_remaining(tvb, offset);
187
188
722
  if (dissector_try_uint(teredo_dissector_table, th_header, next_tvb, pinfo, tree))
189
0
    return;
190
191
722
  call_dissector(data_handle,next_tvb, pinfo, tree);
192
722
}
193
194
static int
195
dissect_teredo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
196
724
{
197
724
  proto_tree *teredo_tree;
198
724
  proto_item *ti;
199
724
  int        offset = 0;
200
724
  static e_teredohdr teredohstruct[4], *teredoh;
201
724
  static int teredoh_count = 0;
202
203
724
  teredoh_count++;
204
724
  if(teredoh_count>=4){
205
181
    teredoh_count=0;
206
181
  }
207
724
  teredoh = &teredohstruct[teredoh_count];
208
209
724
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "Teredo");
210
724
  col_clear(pinfo->cinfo, COL_INFO);
211
212
724
  ti = proto_tree_add_item(tree, proto_teredo, tvb, 0, -1, ENC_NA);
213
724
  teredo_tree = proto_item_add_subtree(ti, ett_teredo);
214
215
724
  teredoh->th_header  = tvb_get_ntohs(tvb, offset);
216
217
724
  if (teredoh->th_header == 1) {
218
5
    offset = parse_teredo_auth(tvb, pinfo, teredo_tree,
219
5
            offset, teredoh);
220
5
    teredoh->th_header  = tvb_get_ntohs(tvb, offset);
221
5
  }
222
719
  else
223
719
    teredoh->th_indtyp  = 0;
224
225
724
  if ( teredoh->th_header == 0 ) {
226
5
    offset = parse_teredo_orig(tvb, pinfo, teredo_tree,
227
5
            offset, teredoh);
228
5
  }
229
230
724
  teredoh->th_ip_v_hl = tvb_get_uint8(tvb, offset);
231
232
724
  decode_teredo_ports(tvb, offset, pinfo, tree, teredoh->th_header /* , teredoh->th_orgport*/);
233
724
  tap_queue_packet(teredo_tap, pinfo, teredoh);
234
724
  return tvb_captured_length(tvb);
235
724
}
236
237
238
static bool
239
dissect_teredo_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
240
0
{
241
0
  uint16_t val;
242
0
  int offset = 0;
243
244
0
  if (tvb_captured_length_remaining(tvb, offset) < 40)
245
0
    return false;
246
247
0
  val = tvb_get_ntohs(tvb, offset);
248
249
0
  if (val == 1) /* possible auth header */
250
0
  {
251
0
    uint8_t idlen, aulen;
252
253
0
    offset += 2;
254
255
0
    idlen = tvb_get_uint8(tvb, offset);
256
0
    offset++;
257
258
0
    aulen = tvb_get_uint8(tvb, offset);
259
0
    offset += 10;
260
261
0
    if (tvb_captured_length_remaining(tvb, offset) < idlen + aulen + 40)
262
0
      return false;
263
264
0
    offset += idlen + aulen;
265
266
0
    val = tvb_get_ntohs(tvb, offset);
267
0
  }
268
269
0
  if (val == 0) /* origin indication */
270
0
  {
271
0
    offset += 8;
272
273
0
    if (tvb_captured_length_remaining(tvb, offset) < 40)
274
0
      return false;
275
276
0
    val = tvb_get_ntohs(tvb, offset);
277
0
  }
278
279
  /*
280
   * We have to check upper-layer packet a little bit otherwise we will
281
   * match -almost- *ANY* packet.
282
   * These checks are in the Teredo specification by the way.
283
   * Unfortunately, that will cause false-negative if the snaplen is too
284
   * short to get the packet entirely.
285
   */
286
0
  if ((val >> 12) == 6) /* IPv6 header */
287
0
  {
288
    /* checks IPv6 payload length */
289
0
    val = tvb_get_ntohs(tvb, offset + 4);
290
0
    offset += 40;
291
292
0
    if (val > 65467)
293
0
      return false; /* length too big for Teredo */
294
295
0
    if (tvb_reported_length_remaining(tvb, offset) != val)
296
0
      return false; /* length mismatch */
297
298
0
    dissect_teredo (tvb, pinfo, tree, data);
299
0
    return true;
300
0
  }
301
302
0
  return false; /* not an IPv6 packet */
303
0
}
304
305
306
void
307
proto_register_teredo(void)
308
14
{
309
14
  static hf_register_info hf[] = {
310
    /* Authentication header */
311
14
    { &hf_teredo_auth,
312
14
    { "Teredo Authentication header", "teredo.auth",
313
14
      FT_NONE, BASE_NONE, NULL, 0x0,
314
14
      NULL, HFILL }},
315
316
14
    { &hf_teredo_auth_idlen,
317
14
    { "Client identifier length", "teredo.auth.idlen",
318
14
      FT_UINT8, BASE_DEC, NULL, 0x0,
319
14
      "Client identifier length (ID-len)", HFILL }},
320
321
14
    { &hf_teredo_auth_aulen,
322
14
    { "Authentication value length", "teredo.auth.aulen",
323
14
      FT_UINT8, BASE_DEC, NULL, 0x0,
324
14
      "Authentication value length (AU-len)", HFILL }},
325
326
14
    { &hf_teredo_auth_id,
327
14
    { "Client identifier", "teredo.auth.id",
328
14
      FT_BYTES, BASE_NONE, NULL, 0x0,
329
14
      "Client identifier (ID)", HFILL }},
330
331
14
    { &hf_teredo_auth_value,
332
14
    { "Authentication value", "teredo.auth.value",
333
14
      FT_BYTES, BASE_NONE, NULL, 0x0,
334
14
      "Authentication value (hash)", HFILL }},
335
336
14
    { &hf_teredo_auth_nonce,
337
14
    { "Nonce value", "teredo.auth.nonce",
338
14
      FT_BYTES, BASE_NONE, NULL, 0x0,
339
14
      "Nonce value prevents spoofing Teredo server.",
340
14
      HFILL }},
341
342
14
    { &hf_teredo_auth_conf,
343
14
    { "Confirmation byte", "teredo.auth.conf",
344
14
      FT_BYTES, BASE_NONE, NULL, 0x0,
345
14
      "Confirmation byte is zero upon successful authentication.",
346
14
      HFILL }},
347
348
    /* Origin indication */
349
14
    { &hf_teredo_orig,
350
14
    { "Teredo Origin Indication header", "teredo.orig",
351
14
      FT_NONE, BASE_NONE, NULL, 0x0,
352
14
      NULL, HFILL }},
353
354
14
    { &hf_teredo_orig_port,
355
14
    { "Origin UDP port", "teredo.orig.port",
356
14
      FT_UINT16, BASE_DEC, NULL, 0x0,
357
14
      NULL, HFILL }},
358
359
14
    { &hf_teredo_orig_addr,
360
14
    { "Origin IPv4 address", "teredo.orig.addr",
361
14
      FT_IPv4, BASE_NONE, NULL, 0x0,
362
14
      NULL, HFILL }},
363
14
  };
364
365
14
  static int *ett[] = {
366
14
    &ett_teredo, &ett_teredo_auth, &ett_teredo_orig
367
14
  };
368
369
14
  module_t *teredo_module;
370
371
14
  proto_teredo = proto_register_protocol("Teredo IPv6 over UDP tunneling", "Teredo", "teredo");
372
14
  proto_register_field_array(proto_teredo, hf, array_length(hf));
373
14
  proto_register_subtree_array(ett, array_length(ett));
374
14
  teredo_handle = register_dissector("teredo", dissect_teredo, proto_teredo);
375
376
/* subdissector code */
377
14
  teredo_dissector_table = register_dissector_table("teredo", "Teredo", proto_teredo, FT_UINT16, BASE_DEC);
378
379
14
  teredo_module = prefs_register_protocol(proto_teredo, NULL);
380
381
14
  prefs_register_obsolete_preference(teredo_module, "heuristic_teredo");
382
383
14
  teredo_tap    = register_tap("teredo");
384
14
}
385
386
void
387
proto_reg_handoff_teredo(void)
388
14
{
389
14
  data_handle   = find_dissector("ipv6");
390
391
14
  dissector_add_uint_with_preference("udp.port", UDP_PORT_TEREDO, teredo_handle);
392
14
  heur_dissector_add("udp", dissect_teredo_heur, "Teredo over UDP", "teredo_udp", proto_teredo, HEURISTIC_DISABLE);
393
14
}
394
395
/*
396
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
397
 *
398
 * Local variables:
399
 * c-basic-offset: 8
400
 * tab-width: 8
401
 * indent-tabs-mode: t
402
 * End:
403
 *
404
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
405
 * :indentSize=8:tabSize=8:noTabs=false:
406
 */