forked from osmocom/wireshark
![Michael Mann](/assets/img/avatar_default.png)
Similar to the "tcp.port" changes in I99604f95d426ad345f4b494598d94178b886eb67, convert dissectors that use "udp.port". More cleanup done on dissectors that use both TCP and UDP dissector tables, so that less preference callbacks exist. Change-Id: If07be9b9e850c244336a7069599cd554ce312dd3 Reviewed-on: https://code.wireshark.org/review/18120 Petri-Dish: Michael Mann <mmann78@netscape.net> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Michael Mann <mmann78@netscape.net>
420 lines
11 KiB
C
420 lines
11 KiB
C
/* packet-teredo.c v.1.0
|
|
* Routines for Teredo packets disassembly
|
|
* draft-huitema-v6ops-teredo-02.txt
|
|
*
|
|
* Copyright 2003, Ragi BEJJANI - 6WIND - <ragi.bejjani@6wind.com>
|
|
* Copyright 2003, Vincent JARDIN - 6WIND - <vincent.jardin@6wind.com>
|
|
* Copyright 2004, Remi DENIS-COURMONT
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <epan/packet.h>
|
|
#include <epan/prefs.h>
|
|
|
|
#include <epan/tap.h>
|
|
|
|
#define UDP_PORT_TEREDO 3544
|
|
|
|
void proto_reg_handoff_teredo(void);
|
|
void proto_register_teredo(void);
|
|
|
|
static int teredo_tap = -1;
|
|
|
|
static int proto_teredo = -1;
|
|
|
|
static int hf_teredo_auth = -1;
|
|
static int hf_teredo_auth_idlen = -1;
|
|
static int hf_teredo_auth_aulen = -1;
|
|
static int hf_teredo_auth_id = -1;
|
|
static int hf_teredo_auth_value = -1;
|
|
static int hf_teredo_auth_nonce = -1;
|
|
static int hf_teredo_auth_conf = -1;
|
|
static int hf_teredo_orig = -1;
|
|
static int hf_teredo_orig_port = -1;
|
|
static int hf_teredo_orig_addr = -1;
|
|
|
|
static gint ett_teredo = -1;
|
|
static gint ett_teredo_auth = -1, ett_teredo_orig = -1;
|
|
|
|
typedef struct {
|
|
guint16 th_indtyp;
|
|
guint8 th_cidlen;
|
|
guint8 th_authdlen;
|
|
guint8 th_nonce[8];
|
|
guint8 th_conf;
|
|
|
|
guint8 th_ip_v_hl;
|
|
guint16 th_header;
|
|
guint16 th_orgport;
|
|
guint32 th_iporgaddr;
|
|
} e_teredohdr;
|
|
|
|
static dissector_table_t teredo_dissector_table;
|
|
/*static heur_dissector_list_t heur_subdissector_list;*/
|
|
static dissector_handle_t data_handle;
|
|
|
|
static int
|
|
parse_teredo_auth(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
|
|
int offset, e_teredohdr *teredoh)
|
|
{
|
|
guint idlen, aulen;
|
|
|
|
col_append_sep_str (pinfo->cinfo, COL_INFO, ", ",
|
|
"Authentication header");
|
|
|
|
teredoh->th_indtyp = 1;
|
|
offset += 2;
|
|
|
|
idlen = tvb_get_guint8(tvb, offset);
|
|
teredoh->th_cidlen = idlen;
|
|
offset++;
|
|
|
|
aulen = tvb_get_guint8(tvb, offset);
|
|
teredoh->th_authdlen = aulen;
|
|
offset++;
|
|
|
|
if (tree) {
|
|
proto_item *ti;
|
|
|
|
ti = proto_tree_add_item(tree, hf_teredo_auth, tvb, offset-4,
|
|
13 + idlen + aulen, ENC_NA);
|
|
tree = proto_item_add_subtree(ti, ett_teredo_auth);
|
|
|
|
proto_tree_add_item(tree, hf_teredo_auth_idlen, tvb,
|
|
offset - 2, 1, ENC_BIG_ENDIAN);
|
|
proto_tree_add_item(tree, hf_teredo_auth_aulen, tvb,
|
|
offset - 1, 1, ENC_BIG_ENDIAN);
|
|
|
|
/* idlen is usually zero */
|
|
if (idlen) {
|
|
proto_tree_add_item(tree, hf_teredo_auth_id, tvb,
|
|
offset, idlen, ENC_NA);
|
|
offset += idlen;
|
|
}
|
|
|
|
/* aulen is usually zero */
|
|
if (aulen) {
|
|
proto_tree_add_item(tree, hf_teredo_auth_value, tvb,
|
|
offset, aulen, ENC_NA);
|
|
offset += aulen;
|
|
}
|
|
|
|
proto_tree_add_item(tree, hf_teredo_auth_nonce, tvb,
|
|
offset, 8, ENC_NA);
|
|
offset += 8;
|
|
|
|
proto_tree_add_item(tree, hf_teredo_auth_conf, tvb,
|
|
offset, 1, ENC_NA);
|
|
offset++;
|
|
}
|
|
else
|
|
offset += idlen + aulen + 9;
|
|
|
|
tvb_memcpy(tvb, teredoh->th_nonce, offset - 9, 8);
|
|
teredoh->th_conf = tvb_get_guint8(tvb, offset - 1);
|
|
|
|
return offset;
|
|
}
|
|
|
|
|
|
static int
|
|
parse_teredo_orig(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
|
|
int offset, e_teredohdr *teredoh)
|
|
{
|
|
proto_item *ti = NULL;
|
|
|
|
col_append_sep_str (pinfo->cinfo, COL_INFO, ", ",
|
|
"Origin indication");
|
|
|
|
if (tree) {
|
|
ti = proto_tree_add_item(tree, hf_teredo_orig, tvb, offset,
|
|
8, ENC_NA);
|
|
tree = proto_item_add_subtree(ti, ett_teredo_orig);
|
|
}
|
|
offset += 2;
|
|
|
|
teredoh->th_orgport = tvb_get_ntohs(tvb, offset);
|
|
if (tree) {
|
|
/*
|
|
* The "usual arithmetic conversions" will convert
|
|
* "teredoh->th_orgport" to an "int" (because all
|
|
* "unsigned short" values will fit in an "int"),
|
|
* which will zero-extend it. This means that
|
|
* complementing it will turn all the zeroes in
|
|
* the upper 16 bits into ones; we just want the
|
|
* lower 16 bits (containing the port number)
|
|
* complemented, with the result zero-extended.
|
|
*
|
|
* That's what the cast is for.
|
|
*/
|
|
proto_tree_add_uint(tree, hf_teredo_orig_port, tvb,
|
|
offset, 2,
|
|
(guint16)~teredoh->th_orgport);
|
|
}
|
|
offset += 2;
|
|
|
|
teredoh->th_iporgaddr = tvb_get_ipv4(tvb, offset);
|
|
if (tree) {
|
|
proto_tree_add_ipv4(tree, hf_teredo_orig_addr, tvb,
|
|
offset, 4, ~teredoh->th_iporgaddr);
|
|
}
|
|
offset += 4;
|
|
|
|
return offset;
|
|
}
|
|
|
|
|
|
/* Determine if there is a sub-dissector and call it. This has been */
|
|
/* separated into a stand alone routine to other protocol dissectors */
|
|
/* can call to it, ie. socks */
|
|
|
|
|
|
static void
|
|
decode_teredo_ports(tvbuff_t *tvb, int offset, packet_info *pinfo,proto_tree *tree, int th_header)
|
|
{
|
|
tvbuff_t *next_tvb;
|
|
|
|
next_tvb = tvb_new_subset_remaining(tvb, offset);
|
|
|
|
if (dissector_try_uint(teredo_dissector_table, th_header, next_tvb, pinfo, tree))
|
|
return;
|
|
|
|
call_dissector(data_handle,next_tvb, pinfo, tree);
|
|
}
|
|
|
|
static int
|
|
dissect_teredo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
|
|
{
|
|
proto_tree *teredo_tree;
|
|
proto_item *ti;
|
|
int offset = 0;
|
|
static e_teredohdr teredohstruct[4], *teredoh;
|
|
static int teredoh_count = 0;
|
|
|
|
teredoh_count++;
|
|
if(teredoh_count>=4){
|
|
teredoh_count=0;
|
|
}
|
|
teredoh = &teredohstruct[teredoh_count];
|
|
|
|
col_set_str(pinfo->cinfo, COL_PROTOCOL, "Teredo");
|
|
col_clear(pinfo->cinfo, COL_INFO);
|
|
|
|
ti = proto_tree_add_item(tree, proto_teredo, tvb, 0, -1, ENC_NA);
|
|
teredo_tree = proto_item_add_subtree(ti, ett_teredo);
|
|
|
|
teredoh->th_header = tvb_get_ntohs(tvb, offset);
|
|
|
|
if (teredoh->th_header == 1) {
|
|
offset = parse_teredo_auth(tvb, pinfo, teredo_tree,
|
|
offset, teredoh);
|
|
teredoh->th_header = tvb_get_ntohs(tvb, offset);
|
|
}
|
|
else
|
|
teredoh->th_indtyp = 0;
|
|
|
|
if ( teredoh->th_header == 0 ) {
|
|
offset = parse_teredo_orig(tvb, pinfo, teredo_tree,
|
|
offset, teredoh);
|
|
}
|
|
|
|
teredoh->th_ip_v_hl = tvb_get_guint8(tvb, offset);
|
|
|
|
decode_teredo_ports(tvb, offset, pinfo, tree, teredoh->th_header /* , teredoh->th_orgport*/);
|
|
tap_queue_packet(teredo_tap, pinfo, teredoh);
|
|
return tvb_captured_length(tvb);
|
|
}
|
|
|
|
|
|
static gboolean
|
|
dissect_teredo_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
|
|
{
|
|
guint16 val;
|
|
int offset = 0;
|
|
|
|
if (tvb_captured_length_remaining(tvb, offset) < 40)
|
|
return FALSE;
|
|
|
|
val = tvb_get_ntohs(tvb, offset);
|
|
|
|
if (val == 1) /* possible auth header */
|
|
{
|
|
guint8 idlen, aulen;
|
|
|
|
offset += 2;
|
|
|
|
idlen = tvb_get_guint8(tvb, offset);
|
|
offset++;
|
|
|
|
aulen = tvb_get_guint8(tvb, offset);
|
|
offset += 10;
|
|
|
|
if (tvb_captured_length_remaining(tvb, offset) < idlen + aulen + 40)
|
|
return FALSE;
|
|
|
|
offset += idlen + aulen;
|
|
|
|
val = tvb_get_ntohs(tvb, offset);
|
|
}
|
|
|
|
if (val == 0) /* origin indication */
|
|
{
|
|
offset += 8;
|
|
|
|
if (tvb_captured_length_remaining(tvb, offset) < 40)
|
|
return FALSE;
|
|
|
|
val = tvb_get_ntohs(tvb, offset);
|
|
}
|
|
|
|
/*
|
|
* We have to check upper-layer packet a little bit otherwise we will
|
|
* match -almost- *ANY* packet.
|
|
* These checks are in the Teredo specification by the way.
|
|
* Unfortunately, that will cause false-negative if the snaplen is too
|
|
* short to get the packet entirely.
|
|
*/
|
|
if ((val >> 12) == 6) /* IPv6 header */
|
|
{
|
|
/* checks IPv6 payload length */
|
|
val = tvb_get_ntohs(tvb, offset + 4);
|
|
offset += 40;
|
|
|
|
if (val > 65467)
|
|
return FALSE; /* length too big for Teredo */
|
|
|
|
if (tvb_reported_length_remaining(tvb, offset) != val)
|
|
return FALSE; /* length mismatch */
|
|
|
|
dissect_teredo (tvb, pinfo, tree, data);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE; /* not an IPv6 packet */
|
|
}
|
|
|
|
|
|
void
|
|
proto_register_teredo(void)
|
|
{
|
|
static hf_register_info hf[] = {
|
|
/* Authentication header */
|
|
{ &hf_teredo_auth,
|
|
{ "Teredo Authentication header", "teredo.auth",
|
|
FT_NONE, BASE_NONE, NULL, 0x0,
|
|
NULL, HFILL }},
|
|
|
|
{ &hf_teredo_auth_idlen,
|
|
{ "Client identifier length", "teredo.auth.idlen",
|
|
FT_UINT8, BASE_DEC, NULL, 0x0,
|
|
"Client identifier length (ID-len)", HFILL }},
|
|
|
|
{ &hf_teredo_auth_aulen,
|
|
{ "Authentication value length", "teredo.auth.aulen",
|
|
FT_UINT8, BASE_DEC, NULL, 0x0,
|
|
"Authentication value length (AU-len)", HFILL }},
|
|
|
|
{ &hf_teredo_auth_id,
|
|
{ "Client identifier", "teredo.auth.id",
|
|
FT_BYTES, BASE_NONE, NULL, 0x0,
|
|
"Client identifier (ID)", HFILL }},
|
|
|
|
{ &hf_teredo_auth_value,
|
|
{ "Authentication value", "teredo.auth.value",
|
|
FT_BYTES, BASE_NONE, NULL, 0x0,
|
|
"Authentication value (hash)", HFILL }},
|
|
|
|
{ &hf_teredo_auth_nonce,
|
|
{ "Nonce value", "teredo.auth.nonce",
|
|
FT_BYTES, BASE_NONE, NULL, 0x0,
|
|
"Nonce value prevents spoofing Teredo server.",
|
|
HFILL }},
|
|
|
|
{ &hf_teredo_auth_conf,
|
|
{ "Confirmation byte", "teredo.auth.conf",
|
|
FT_BYTES, BASE_NONE, NULL, 0x0,
|
|
"Confirmation byte is zero upon successful authentication.",
|
|
HFILL }},
|
|
|
|
/* Origin indication */
|
|
{ &hf_teredo_orig,
|
|
{ "Teredo Origin Indication header", "teredo.orig",
|
|
FT_NONE, BASE_NONE, NULL, 0x0,
|
|
"Teredo Origin Indication", HFILL }},
|
|
|
|
{ &hf_teredo_orig_port,
|
|
{ "Origin UDP port", "teredo.orig.port",
|
|
FT_UINT16, BASE_DEC, NULL, 0x0,
|
|
NULL, HFILL }},
|
|
|
|
{ &hf_teredo_orig_addr,
|
|
{ "Origin IPv4 address", "teredo.orig.addr",
|
|
FT_IPv4, BASE_NONE, NULL, 0x0,
|
|
NULL, HFILL }},
|
|
};
|
|
|
|
static gint *ett[] = {
|
|
&ett_teredo, &ett_teredo_auth, &ett_teredo_orig
|
|
};
|
|
|
|
module_t *teredo_module;
|
|
|
|
proto_teredo = proto_register_protocol(
|
|
"Teredo IPv6 over UDP tunneling", "Teredo", "teredo");
|
|
proto_register_field_array(proto_teredo, hf, array_length(hf));
|
|
proto_register_subtree_array(ett, array_length(ett));
|
|
|
|
/* subdissector code */
|
|
teredo_dissector_table = register_dissector_table("teredo", "Teredo", proto_teredo, FT_UINT16, BASE_DEC);
|
|
|
|
teredo_module = prefs_register_protocol(proto_teredo, NULL);
|
|
|
|
prefs_register_obsolete_preference(teredo_module, "heuristic_teredo");
|
|
|
|
}
|
|
|
|
void
|
|
proto_reg_handoff_teredo(void)
|
|
{
|
|
dissector_handle_t teredo_handle;
|
|
|
|
teredo_handle = create_dissector_handle(dissect_teredo, proto_teredo);
|
|
data_handle = find_dissector("ipv6");
|
|
teredo_tap = register_tap("teredo");
|
|
|
|
dissector_add_uint_with_preference("udp.port", UDP_PORT_TEREDO, teredo_handle);
|
|
heur_dissector_add("udp", dissect_teredo_heur, "Teredo over UDP", "teredo_udp", proto_teredo, HEURISTIC_DISABLE);
|
|
}
|
|
|
|
/*
|
|
* Editor modelines - http://www.wireshark.org/tools/modelines.html
|
|
*
|
|
* Local variables:
|
|
* c-basic-offset: 8
|
|
* tab-width: 8
|
|
* indent-tabs-mode: t
|
|
* End:
|
|
*
|
|
* vi: set shiftwidth=8 tabstop=8 noexpandtab:
|
|
* :indentSize=8:tabSize=8:noTabs=false:
|
|
*/
|