2 * Routines for Session Traversal Utilities for NAT (STUN) dissection
3 * Copyright 2003, Shiang-Ming Huang <smhuang@pcs.csie.nctu.edu.tw>
4 * Copyright 2006, Marc Petit-Huguenin <marc@petit-huguenin.org>
5 * Copyright 2007-2008, 8x8 Inc. <petithug@8x8.com>
6 * Copyright 2008, Gael Breard <gael@breard.org>
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1998 Gerald Combs
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 * Please refer to the following specs for protocol detail:
29 * - draft-ietf-behave-rfc3489bis-17
30 * - draft-ietf-mmusic-ice-19
31 * - draft-ietf-behave-nat-behavior-discovery-03
32 * - draft-ietf-behave-turn-10
33 * - draft-ietf-behave-turn-ipv6-03
42 #include <epan/packet.h>
43 #include <epan/conversation.h>
44 #include <epan/ipproto.h>
45 #include <packet-tcp.h>
46 #include <packet-udp.h>
48 /* heuristic subdissectors */
49 static heur_dissector_list_t heur_subdissector_list;
51 /* data dissector handle */
52 static dissector_handle_t data_handle;
54 /* Initialize the protocol and registered fields */
55 static int proto_stun = -1;
57 static int hf_stun_channel = -1;
59 static int hf_stun_type = -1;
60 static int hf_stun_type_class = -1;
61 static int hf_stun_type_method = -1;
62 static int hf_stun_type_method_assignment = -1;
63 static int hf_stun_length = -1;
64 static int hf_stun_cookie = -1;
65 static int hf_stun_id = -1;
66 static int hf_stun_attributes = -1;
67 static int hf_stun_response_in = -1;
68 static int hf_stun_response_to = -1;
69 static int hf_stun_time = -1;
70 static int hf_stun_duplicate = -1;
71 static int hf_stun_attr = -1;
73 static int stun_att_type = -1; /* STUN attribute fields */
74 static int stun_att_length = -1;
75 static int stun_att_family = -1;
76 static int stun_att_type_comprehension = -1;
77 static int stun_att_type_assignment = -1;
78 static int stun_att_ipv4 = -1;
79 static int stun_att_ipv6 = -1;
80 static int stun_att_port = -1;
81 static int stun_att_username = -1;
82 static int stun_att_padding = -1;
83 static int stun_att_hmac = -1;
84 static int stun_att_crc32 = -1;
85 static int stun_att_error_class = -1;
86 static int stun_att_error_number = -1;
87 static int stun_att_error_reason = -1;
88 static int stun_att_realm = -1;
89 static int stun_att_nonce = -1;
90 static int stun_att_unknown = -1;
91 static int stun_att_xor_ipv4 = -1;
92 static int stun_att_xor_ipv6 = -1;
93 static int stun_att_xor_port = -1;
94 static int stun_att_icmp_type = -1;
95 static int stun_att_icmp_code = -1;
96 static int stun_att_software = -1;
97 static int stun_att_priority = -1;
98 static int stun_att_tie_breaker = -1;
99 static int stun_att_change_ip = -1;
100 static int stun_att_change_port = -1;
101 static int stun_att_cache_timeout = -1;
102 static int stun_att_token = -1;
103 static int stun_att_reserve_next = -1;
104 static int stun_att_reserved = -1;
105 static int stun_att_value = -1;
106 static int stun_att_transp = -1;
107 static int stun_att_bandwidth = -1;
108 static int stun_att_lifetime = -1;
109 static int stun_att_channelnum = -1;
112 /* Structure containing transaction specific information */
113 typedef struct _stun_transaction_t {
117 } stun_transaction_t;
119 /* Structure containing conversation specific information */
120 typedef struct _stun_conv_info_t {
121 emem_tree_t *transaction_pdus;
125 /* Message classes */
126 #define REQUEST 0x0000
127 #define INDICATION 0x0001
128 #define RESPONSE 0x0002
129 #define ERROR_RESPONSE 0x0003
133 #define BINDING 0x0001 /* draft-ietf-behave-rfc3489bis-17 */
134 #define ALLOCATE 0x0003 /* draft-ietf-behave-turn-10*/
135 #define REFRESH 0x0004 /* draft-ietf-behave-turn-10*/
136 #define CHANNELBIND 0x0009 /* draft-ietf-behave-turn-10*/
137 #define CREATE_PERMISSION 0x0008 /* draft-ietf-behave-turn-10 */
139 #define SEND 0x0006 /* draft-ietf-behave-turn-10*/
140 #define DATA_IND 0x0007 /* draft-ietf-behave-turn-10*/
143 /* Attribute Types */
144 /* Comprehension-required range (0x0000-0x7FFF) */
145 #define MAPPED_ADDRESS 0x0001 /* draft-ietf-behave-rfc3489bis-17 */
146 #define CHANGE_REQUEST 0x0003 /* draft-ietf-behave-nat-behavior-discovery-03 */
147 #define USERNAME 0x0006 /* draft-ietf-behave-rfc3489bis-17 */
148 #define MESSAGE_INTEGRITY 0x0008 /* draft-ietf-behave-rfc3489bis-17 */
149 #define ERROR_CODE 0x0009 /* draft-ietf-behave-rfc3489bis-17 */
150 #define UNKNOWN_ATTRIBUTES 0x000a /* draft-ietf-behave-rfc3489bis-17 */
151 #define CHANNEL_NUMBER 0x000c /* draft-ietf-behave-turn-10 */
152 #define LIFETIME 0x000d /* draft-ietf-behave-turn-10 */
153 #define BANDWIDTH 0x0010 /* turn-07 */
154 #define XOR_PEER_ADDRESS 0x0012 /* draft-ietf-behave-turn-10 */
155 #define DATA 0x0013 /* draft-ietf-behave-turn-10 */
156 #define REALM 0x0014 /* draft-ietf-behave-rfc3489bis-17 */
157 #define NONCE 0x0015 /* draft-ietf-behave-rfc3489bis-17 */
158 #define XOR_RELAYED_ADDRESS 0x0016 /* draft-ietf-behave-turn-10 */
159 #define REQUESTED_ADDRESS_TYPE 0x0017 /* draft-ietf-behave-turn-ipv6-03 */
160 #define EVEN_PORT 0x0018 /* draft-ietf-behave-turn-10 */
161 #define REQUESTED_TRANSPORT 0x0019 /* draft-ietf-behave-turn-10 */
162 #define DONT_FRAGMENT 0x001a /* draft-ietf-behave-turn-10 */
163 #define XOR_MAPPED_ADDRESS 0x0020 /* draft-ietf-behave-rfc3489bis-17 */
164 #define RESERVATION_TOKEN 0x0022 /* draft-ietf-behave-turn-10 */
165 #define PRIORITY 0x0024 /* draft-ietf-mmusic-ice-19 */
166 #define USE_CANDIDATE 0x0025 /* draft-ietf-mmusic-ice-19 */
167 #define PADDING 0x0026 /* draft-ietf-behave-nat-behavior-discovery-03 */
168 #define XOR_RESPONSE_TARGET 0x0027 /* draft-ietf-behave-nat-behavior-discovery-03 */
169 #define XOR_REFLECTED_FROM 0x0028 /* draft-ietf-behave-nat-behavior-discovery-03 */
170 #define ICMP 0x0030 /* Moved from TURN to a future I-D */
171 /* Comprehension-optional range (0x8000-0xFFFF) */
172 #define SOFTWARE 0x8022 /* draft-ietf-behave-rfc3489bis-17 */
173 #define ALTERNATE_SERVER 0x8023 /* draft-ietf-behave-rfc3489bis-17 */
174 #define CACHE_TIMEOUT 0x8027 /* draft-ietf-behave-nat-behavior-discovery-03 */
175 #define FINGERPRINT 0x8028 /* draft-ietf-behave-rfc3489bis-17 */
176 #define ICE_CONTROLLED 0x8029 /* draft-ietf-mmusic-ice-19 */
177 #define ICE_CONTROLLING 0x802a /* draft-ietf-mmusic-ice-19 */
178 #define RESPONSE_ORIGIN 0x802b /* draft-ietf-behave-nat-behavior-discovery-03 */
179 #define OTHER_ADDRESS 0x802c /* draft-ietf-behave-nat-behavior-discovery-03 */
182 #define PROTO_NUM_UDP 17
183 #define PROTO_NUM_TCP 6
184 #define PROTO_NUM_ERR 255
186 #define TURN_REQUESTED_PROPS_EVEN_PORT 0x01
187 #define TURN_REQUESTED_PROPS_PAIR_OF_PORTS 0x02
189 #define TURN_CHANNEL_NUMBER_MIN 0x4000
190 #define TURN_CHANNEL_NUMBER_MAX 0xFFFE
198 /* Initialize the subtree pointers */
199 static gint ett_stun = -1;
200 static gint ett_stun_type = -1;
201 static gint ett_stun_att_all= -1;
202 static gint ett_stun_att = -1;
203 static gint ett_stun_att_type = -1;
205 #define UDP_PORT_STUN 3478
206 #define TCP_PORT_STUN 3478
208 #define STUN_HDR_LEN ((guint)20) /* STUN message header length */
209 #define ATTR_HDR_LEN 4 /* STUN attribute header length */
210 #define CHANNEL_DATA_HDR_LEN 4 /* TURN CHANNEL-DATA Message hdr length */
211 #define MIN_HDR_LEN 4
213 static const value_string transportnames[] = {
219 static const value_string classes[] = {
220 {REQUEST , "Request"},
221 {INDICATION , "Indication"},
222 {RESPONSE , "Success Response"},
223 {ERROR_RESPONSE, "Error Response"},
227 static const value_string methods[] = {
228 {BINDING , "Binding"},
229 {ALLOCATE , "Allocate"},
230 {REFRESH , "Refresh"},
231 {CHANNELBIND , "Channel-Bind"},
234 {CREATE_PERMISSION, "CreatePermission"},
240 static const value_string attributes[] = {
241 {MAPPED_ADDRESS , "MAPPED-ADDRESS"},
242 {CHANGE_REQUEST , "CHANGE_REQUEST"},
243 {USERNAME , "USERNAME"},
244 {MESSAGE_INTEGRITY , "MESSAGE-INTEGRITY"},
245 {ERROR_CODE , "ERROR-CODE"},
246 {UNKNOWN_ATTRIBUTES , "UNKNOWN-ATTRIBUTES"},
247 {CHANNEL_NUMBER , "CHANNEL-NUMBER"},
248 {LIFETIME , "LIFETIME"},
249 {BANDWIDTH , "BANDWIDTH"},
250 {XOR_PEER_ADDRESS , "XOR-PEER-ADDRESS"},
254 {XOR_RELAYED_ADDRESS , "XOR-RELAYED-ADDRESS"},
255 {REQUESTED_ADDRESS_TYPE, "REQUESTED-ADDRESS-TYPE"},
256 {EVEN_PORT , "EVEN-PORT"},
257 {REQUESTED_TRANSPORT , "REQUESTED-TRANSPORT"},
258 {DONT_FRAGMENT , "DONT-FRAGMENT"},
259 {XOR_MAPPED_ADDRESS , "XOR-MAPPED-ADDRESS"},
260 {RESERVATION_TOKEN , "RESERVATION-TOKEN"},
261 {PRIORITY , "PRIORITY"},
262 {USE_CANDIDATE , "USE-CANDIDATE"},
263 {PADDING , "PADDING"},
264 {XOR_RESPONSE_TARGET , "XOR-RESPONSE-TARGET"},
265 {XOR_REFLECTED_FROM , "XOR-REFELECTED-FROM"},
267 {SOFTWARE , "SOFTWARE"},
268 {ALTERNATE_SERVER , "ALTERNATE-SERVER"},
269 {CACHE_TIMEOUT , "CACHE-TIMEOUT"},
270 {FINGERPRINT , "FINGERPRINT"},
271 {ICE_CONTROLLED , "ICE-CONTROLLED"},
272 {ICE_CONTROLLING , "ICE-CONTROLLING"},
273 {RESPONSE_ORIGIN , "RESPONSE-ORIGIN"},
274 {OTHER_ADDRESS , "OTHER-ADDRESS"},
278 static const value_string assignments[] = {
279 {0x0000, "IETF Review"},
280 {0x0001, "Designated Expert"},
284 static const value_string comprehensions[] = {
285 {0x0000, "Required"},
286 {0x0001, "Optional"},
290 static const value_string attributes_reserve_next[] = {
291 {0, "No reservation"},
292 {1, "Reserve next port number"},
296 static const value_string attributes_properties_p[] = {
297 {0, "All allocation"},
298 {1, "Preserving allocation"},
302 static const value_string attributes_family[] = {
308 static const value_string error_code[] = {
309 {300, "Try Alternate"},/* rfc3489bis-15 */
310 {400, "Bad Request"},/* rfc3489bis-15 */
311 {401, "Unauthorized"},/* rfc3489bis-15 */
312 {420, "Unknown Attribute"},/* rfc3489bis-15 */
313 {437, "Allocation Mismatch"},/* turn-07 */
314 {438, "Stale Nonce"},/* rfc3489bis-15 */
315 {439, "Wrong Credentials"}, /* turn-07 - collision 38=>39 */
316 {442, "Unsupported Transport Protocol"},/* turn-07 */
317 {440, "Address Family not Supported"}, /* turn-ipv6-04 */
318 {481, "Connection does not exist"}, /* nat-behavior-discovery-03 */
319 {486, "Allocation Quota Reached"},/* turn-07 */
320 {500, "Server Error"},/* rfc3489bis-15 */
321 {503, "Service Unavailable"}, /* nat-behavior-discovery-03 */
322 {507, "Insufficient Bandwidth Capacity"},/* turn-07 */
323 {508, "Insufficient Port Capacity"},/* turn-07 */
324 {600, "Global Failure"},
330 get_stun_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
332 guint16 type = tvb_get_ntohs(tvb, offset);
333 guint16 length = tvb_get_ntohs(tvb, offset+2);
338 /* two first bits not NULL => should be a channel-data message */
339 res = (guint) ((length + CHANNEL_DATA_HDR_LEN +3) & -4);
343 /* Normal STUN message */
344 res = (guint) length + STUN_HDR_LEN;
350 dissect_stun_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
353 proto_tree *stun_tree;
354 proto_tree *stun_type_tree;
355 proto_tree *att_all_tree;
356 proto_tree *att_type_tree;
357 proto_tree *att_tree;
360 guint16 msg_type_method;
361 guint16 msg_type_class;
362 const char *msg_class_str;
363 const char *msg_method_str;
366 const char *att_type_str;
369 guint magic_cookie_first_word;
372 conversation_t *conversation=NULL;
373 stun_conv_info_t *stun_info;
374 stun_transaction_t * stun_trans;
375 emem_tree_key_t transaction_id_key[2];
376 guint32 transaction_id[3];
379 * First check if the frame is really meant for us.
383 len = tvb_length(tvb);
387 /* First, make sure we have enough data to do the check. */
388 if (len < MIN_HDR_LEN)
391 msg_type = tvb_get_ntohs(tvb, 0);
392 msg_length = tvb_get_ntohs(tvb, 2);
394 if (msg_type & 0xC000)
396 /* two first bits not NULL => should be a channel-data message */
397 if (msg_type == 0xFFFF)
399 /* note that padding is only mandatory over streaming
401 msg_total_len = (guint) ((msg_length + CHANNEL_DATA_HDR_LEN +3) & -4) ;
403 /* check if payload enough */
404 if (len != msg_total_len) {
405 if (pinfo->ipproto != IP_PROTO_UDP) {
408 /* recalculate the total length without padding */
409 msg_total_len = (guint) msg_length + CHANNEL_DATA_HDR_LEN;
410 if (len != msg_total_len)
416 /* Normal STUN message */
417 msg_total_len = (guint) msg_length + STUN_HDR_LEN;
418 if (len < STUN_HDR_LEN)
420 /* Check if it is really a STUN message */
421 if ( tvb_get_ntohl(tvb, 4) != 0x2112a442)
424 /* check if payload enough */
425 if (len != msg_total_len)
429 /* The message seems to be a valid STUN message! */
431 col_set_str(pinfo->cinfo, COL_PROTOCOL, "STUN");
433 /* BEGIN of CHANNEL-DATA specific section */
434 if (msg_type & 0xC000)
438 guint reported_len, new_len;
439 /* two first bits not NULL => should be a channel-data message*/
441 /* Clear out stuff in the info column */
442 col_set_str(pinfo->cinfo, COL_INFO, "ChannelData TURN Message");
445 return tvb_length(tvb);
446 ti = proto_tree_add_item(
447 tree, proto_stun, tvb, 0,
448 CHANNEL_DATA_HDR_LEN,
450 proto_item_append_text(ti, ", TURN ChannelData Message");
451 stun_tree = proto_item_add_subtree(ti, ett_stun);
452 proto_tree_add_item(stun_tree, hf_stun_channel, tvb, offset, 2, FALSE); offset += 2;
453 data_length = tvb_get_ntohs(tvb, 2);
454 proto_tree_add_item(stun_tree, hf_stun_length, tvb, offset, 2, FALSE); offset += 2;
457 new_len = tvb_length_remaining(tvb, CHANNEL_DATA_HDR_LEN);
458 reported_len = tvb_reported_length_remaining(tvb,
459 CHANNEL_DATA_HDR_LEN);
460 if (data_length < reported_len) {
461 reported_len = data_length;
463 next_tvb = tvb_new_subset(tvb, CHANNEL_DATA_HDR_LEN, new_len,
467 if (!dissector_try_heuristic(heur_subdissector_list,
468 next_tvb, pinfo, tree)) {
469 call_dissector_only(data_handle,next_tvb, pinfo, tree);
472 return tvb_length(tvb);
474 /* END of CHANNEL-DATA specific section */
476 /* At this stage, we know this is a standard stun message */
478 /* Create the transaction key which may be used
479 to track the conversation */
480 transaction_id[0] = tvb_get_ntohl(tvb, 8);
481 transaction_id[1] = tvb_get_ntohl(tvb, 12);
482 transaction_id[2] = tvb_get_ntohl(tvb, 16);
484 transaction_id_key[0].length = 3;
485 transaction_id_key[0].key = transaction_id;
486 transaction_id_key[1].length = 0;
487 transaction_id_key[1].key = NULL;
489 msg_type_class = ((msg_type & 0x0010) >> 4) | ((msg_type & 0x0100) >> 7) ;
490 msg_type_method = (msg_type & 0x000F) | ((msg_type & 0x00E0) >> 1) | ((msg_type & 0x3E00) >> 2);
492 /* Do we already have a conversation ? */
494 find_conversation(pinfo->fd->num,
495 &pinfo->src, &pinfo->dst,
497 pinfo->srcport, pinfo->destport, 0);
498 if (conversation == NULL) {
499 /* We don't yet have a conversation, so create one. */
500 conversation = conversation_new(pinfo->fd->num,
501 &pinfo->src, &pinfo->dst,
503 pinfo->srcport, pinfo->destport, 0);
506 * Do we already have a state structure for this conv
508 stun_info = conversation_get_proto_data(conversation, proto_stun);
510 /* No. Attach that information to the conversation, and add
511 * it to the list of information structures.
513 stun_info = se_alloc(sizeof(stun_conv_info_t));
514 stun_info->transaction_pdus=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "stun_transaction_pdus");
515 conversation_add_proto_data(conversation, proto_stun, stun_info);
518 if (!pinfo->fd->flags.visited) {
520 se_tree_lookup32_array(stun_info->transaction_pdus,
521 transaction_id_key)) == NULL) {
522 stun_trans=se_alloc(sizeof(stun_transaction_t));
523 stun_trans->req_frame=0;
524 stun_trans->rep_frame=0;
525 stun_trans->req_time=pinfo->fd->abs_ts;
526 se_tree_insert32_array(stun_info->transaction_pdus,
531 if (msg_type_class == REQUEST) {
532 /* This is a request */
533 if (stun_trans->req_frame == 0) {
534 stun_trans->req_frame=pinfo->fd->num;
538 /* This is a catch-all for all non-request messages */
539 if (stun_trans->rep_frame == 0) {
540 stun_trans->rep_frame=pinfo->fd->num;
545 stun_trans=se_tree_lookup32_array(stun_info->transaction_pdus,
550 /* create a "fake" pana_trans structure */
551 stun_trans=ep_alloc(sizeof(stun_transaction_t));
552 stun_trans->req_frame=0;
553 stun_trans->rep_frame=0;
554 stun_trans->req_time=pinfo->fd->abs_ts;
558 msg_class_str = match_strval(msg_type_class, classes);
559 msg_method_str = match_strval(msg_type_method, methods);
561 if (msg_method_str == NULL)
562 msg_method_str = "Unknown";
564 if(check_col(pinfo->cinfo,COL_INFO)) {
565 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
566 msg_method_str, msg_class_str);
569 ti = proto_tree_add_item(tree, proto_stun, tvb, 0, -1, FALSE);
571 stun_tree = proto_item_add_subtree(ti, ett_stun);
574 if (msg_type_class == REQUEST) {
575 if (stun_trans->req_frame != pinfo->fd->num) {
577 it=proto_tree_add_uint(stun_tree, hf_stun_duplicate,
579 stun_trans->req_frame);
580 PROTO_ITEM_SET_GENERATED(it);
582 if (stun_trans->rep_frame) {
584 it=proto_tree_add_uint(stun_tree, hf_stun_response_in,
586 stun_trans->rep_frame);
587 PROTO_ITEM_SET_GENERATED(it);
591 /* Retransmission control */
592 if (stun_trans->rep_frame != pinfo->fd->num) {
594 it=proto_tree_add_uint(stun_tree, hf_stun_duplicate,
596 stun_trans->rep_frame);
597 PROTO_ITEM_SET_GENERATED(it);
599 if (msg_type_class == RESPONSE || msg_type_class == ERROR_RESPONSE) {
600 /* This is a response */
601 if (stun_trans->req_frame) {
605 it=proto_tree_add_uint(stun_tree, hf_stun_response_to, tvb, 0, 0,
606 stun_trans->req_frame);
607 PROTO_ITEM_SET_GENERATED(it);
609 nstime_delta(&ns, &pinfo->fd->abs_ts, &stun_trans->req_time);
610 it=proto_tree_add_time(stun_tree, hf_stun_time, tvb, 0, 0, &ns);
611 PROTO_ITEM_SET_GENERATED(it);
617 ti = proto_tree_add_uint_format(stun_tree, hf_stun_type, tvb, 0, 2,
618 msg_type, "Message Type: 0x%04x (%s %s)", msg_type, msg_method_str, msg_class_str);
619 stun_type_tree = proto_item_add_subtree(ti, ett_stun_type);
620 proto_tree_add_uint(stun_type_tree, hf_stun_type_class, tvb, 0, 2, msg_type);
621 ti = proto_tree_add_text(stun_type_tree, tvb, 0, 2, "%s (%d)", msg_class_str, msg_type_class);
622 PROTO_ITEM_SET_GENERATED(ti);
623 proto_tree_add_uint(stun_type_tree, hf_stun_type_method, tvb, 0, 2, msg_type);
624 ti = proto_tree_add_text(stun_type_tree, tvb, 0, 2, "%s (0x%03x)", msg_method_str, msg_type_method);
625 PROTO_ITEM_SET_GENERATED(ti);
626 proto_tree_add_uint(stun_type_tree, hf_stun_type_method_assignment, tvb, 0, 2, msg_type);
627 ti = proto_tree_add_text(stun_type_tree, tvb, 0, 2, "%s (%d)", match_strval((msg_type & 0x2000) >> 13, assignments), (msg_type & 0x2000) >> 13);
628 PROTO_ITEM_SET_GENERATED(ti);
630 proto_tree_add_uint(stun_tree, hf_stun_length, tvb, 2, 2, msg_length);
631 proto_tree_add_item(stun_tree, hf_stun_cookie, tvb, 4, 4, FALSE);
632 proto_tree_add_item(stun_tree, hf_stun_id, tvb, 8, 12, FALSE);
634 /* Remember this (in host order) so we can show clear xor'd addresses */
635 magic_cookie_first_word = tvb_get_ntohl(tvb, 4);
637 if (msg_length > 0) {
638 ti = proto_tree_add_item(stun_tree, hf_stun_attributes, tvb, STUN_HDR_LEN, msg_length, FALSE);
639 att_all_tree = proto_item_add_subtree(ti, ett_stun_att_all);
641 offset = STUN_HDR_LEN;
643 while (msg_length > 0) {
644 att_type = tvb_get_ntohs(tvb, offset); /* Type field in attribute header */
645 att_length = tvb_get_ntohs(tvb, offset+2); /* Length field in attribute header */
646 att_type_str = match_strval(att_type, attributes);
647 if (att_type_str == NULL)
648 att_type_str = "Unknown";
649 ti = proto_tree_add_uint_format(att_all_tree, hf_stun_attr,
650 tvb, offset, ATTR_HDR_LEN+att_length,
651 att_type, "%s", att_type_str);
652 att_tree = proto_item_add_subtree(ti, ett_stun_att);
653 ti = proto_tree_add_uint(att_tree, stun_att_type, tvb,
654 offset, 2, att_type);
655 att_type_tree = proto_item_add_subtree(ti, ett_stun_att_type);
656 proto_tree_add_uint(att_type_tree, stun_att_type_comprehension, tvb, offset, 2, att_type);
657 ti = proto_tree_add_text(att_type_tree, tvb, offset, 2,
659 match_strval((att_type & 0x8000) >> 15, comprehensions),
660 (att_type & 0x8000) >> 15);
661 PROTO_ITEM_SET_GENERATED(ti);
662 proto_tree_add_uint(att_type_tree, stun_att_type_assignment, tvb, offset, 2, att_type);
663 ti = proto_tree_add_text(att_type_tree, tvb, offset, 2,
665 match_strval((att_type & 0x4000) >> 14, assignments),
666 (att_type & 0x4000) >> 14);
667 PROTO_ITEM_SET_GENERATED(ti);
670 if (ATTR_HDR_LEN+att_length > msg_length) {
671 proto_tree_add_uint_format(att_tree,
672 stun_att_length, tvb, offset, 2,
674 "Attribute Length: %u (bogus, goes past the end of the message)",
678 proto_tree_add_uint(att_tree, stun_att_length, tvb,
679 offset, 2, att_length);
683 case ALTERNATE_SERVER:
684 case RESPONSE_ORIGIN:
688 proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset, 1, 1);
691 proto_tree_add_item(att_tree, stun_att_family, tvb, offset+1, 1, FALSE);
694 proto_tree_add_item(att_tree, stun_att_port, tvb, offset+2, 2, FALSE);
695 switch (tvb_get_guint8(tvb, offset+1)) {
699 proto_tree_add_item(att_tree, stun_att_ipv4, tvb, offset+4, 4, FALSE);
703 ip = tvb_get_ipv4(tvb,offset+4);
704 ipstr = ip_to_str((guint8*)&ip);
705 proto_item_append_text(att_tree, ": %s:%d", ipstr,tvb_get_ntohs(tvb,offset+2));
706 if(check_col(pinfo->cinfo,COL_INFO)) {
708 pinfo->cinfo, COL_INFO,
710 val_to_str(att_type, attributes, "Unknown"),
712 tvb_get_ntohs(tvb,offset+2)
721 proto_tree_add_item(att_tree, stun_att_ipv6, tvb, offset+4, 16, FALSE);
729 proto_tree_add_item(att_tree, stun_att_change_ip, tvb, offset, 4, FALSE);
730 proto_tree_add_item(att_tree, stun_att_change_port, tvb, offset, 4, FALSE);
734 proto_tree_add_item(att_tree, stun_att_username, tvb, offset, att_length, FALSE);
735 proto_item_append_text(att_tree, ": %s", tvb_get_ephemeral_string(tvb, offset, att_length));
736 if(check_col(pinfo->cinfo,COL_INFO)) {
738 pinfo->cinfo, COL_INFO,
740 tvb_get_ephemeral_string(tvb,offset, att_length)
743 if (att_length % 4 != 0)
744 proto_tree_add_uint(att_tree, stun_att_padding,
745 tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
748 case MESSAGE_INTEGRITY:
751 proto_tree_add_item(att_tree, stun_att_hmac, tvb, offset, att_length, FALSE);
757 proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset, 2, 2);
760 proto_tree_add_item(att_tree, stun_att_error_class, tvb, offset+2, 1, FALSE);
763 proto_tree_add_item(att_tree, stun_att_error_number, tvb, offset+3, 1, FALSE);
765 int human_error_num = tvb_get_guint8(tvb, offset+2) * 100 + tvb_get_guint8(tvb, offset+3);
766 proto_item_append_text(
769 human_error_num, /* human readable error code */
770 val_to_str(human_error_num, error_code, "*Unknown error code*")
772 if(check_col(pinfo->cinfo,COL_INFO)) {
774 pinfo->cinfo, COL_INFO,
775 " error-code: %d (%s)",
777 val_to_str(human_error_num, error_code, "*Unknown error code*")
783 proto_tree_add_item(att_tree, stun_att_error_reason, tvb, offset+4, att_length-4, FALSE);
785 proto_item_append_text(att_tree, ": %s", tvb_get_ephemeral_string(tvb, offset+4, att_length-4));
786 if(check_col(pinfo->cinfo,COL_INFO)) {
788 pinfo->cinfo, COL_INFO,
790 tvb_get_ephemeral_string(tvb, offset+4, att_length-4)
794 if (att_length % 4 != 0)
795 proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
798 case UNKNOWN_ATTRIBUTES:
799 for (i = 0; i < att_length; i += 2)
800 proto_tree_add_item(att_tree, stun_att_unknown, tvb, offset+i, 2, FALSE);
801 if (att_length % 4 != 0)
802 proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
806 proto_tree_add_item(att_tree, stun_att_realm, tvb, offset, att_length, FALSE);
807 proto_item_append_text(att_tree, ": %s", tvb_get_ephemeral_string(tvb, offset, att_length));
808 if(check_col(pinfo->cinfo,COL_INFO)) {
810 pinfo->cinfo, COL_INFO,
812 tvb_get_ephemeral_string(tvb,offset, att_length)
815 if (att_length % 4 != 0)
816 proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
820 proto_tree_add_item(att_tree, stun_att_nonce, tvb, offset, att_length, FALSE);
821 proto_item_append_text(att_tree, ": %s", tvb_get_ephemeral_string(tvb, offset, att_length));
822 if(check_col(pinfo->cinfo,COL_INFO)) {
824 pinfo->cinfo, COL_INFO,
828 if (att_length % 4 != 0)
829 proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
832 case XOR_MAPPED_ADDRESS:
833 case XOR_PEER_ADDRESS:
834 case XOR_RELAYED_ADDRESS:
835 case XOR_RESPONSE_TARGET:
836 case XOR_REFLECTED_FROM:
839 proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset, 1, 1);
842 proto_tree_add_item(att_tree, stun_att_family, tvb, offset+1, 1, FALSE);
845 proto_tree_add_item(att_tree, stun_att_xor_port, tvb, offset+2, 2, FALSE);
847 /* Show the port 'in the clear'
848 XOR (host order) transid with (host order) xor-port.
849 Add host-order port into tree. */
850 ti = proto_tree_add_uint(att_tree, stun_att_port, tvb, offset+2, 2,
851 tvb_get_ntohs(tvb, offset+2) ^
852 (magic_cookie_first_word >> 16));
853 PROTO_ITEM_SET_GENERATED(ti);
857 switch (tvb_get_guint8(tvb, offset+1)) {
861 proto_tree_add_item(att_tree, stun_att_xor_ipv4, tvb, offset+4, 4, FALSE);
863 /* Show the address 'in the clear'.
864 XOR (host order) transid with (host order) xor-address.
865 Add in network order tree. */
866 ti = proto_tree_add_ipv4(att_tree, stun_att_ipv4, tvb, offset+4, 4,
867 g_htonl(tvb_get_ntohl(tvb, offset+4) ^
868 magic_cookie_first_word));
869 PROTO_ITEM_SET_GENERATED(ti);
875 ip = g_htonl(tvb_get_ntohl(tvb, offset+4) ^ magic_cookie_first_word);
876 ipstr = ip_to_str((guint8*)&ip);
877 port = tvb_get_ntohs(tvb, offset+2) ^ (magic_cookie_first_word >> 16);
878 proto_item_append_text(att_tree, ": %s:%d", ipstr, port);
879 if(check_col(pinfo->cinfo,COL_INFO)) {
881 pinfo->cinfo, COL_INFO,
883 val_to_str(att_type, attributes, "Unknown"),
894 proto_tree_add_item(att_tree, stun_att_xor_ipv6, tvb, offset+4, 16, FALSE);
897 IPv6[0] = g_htonl(tvb_get_ntohl(tvb, offset+4) ^ magic_cookie_first_word);
898 IPv6[1] = g_htonl(tvb_get_ntohl(tvb, offset+8) ^ transaction_id[0]);
899 IPv6[2] = g_htonl(tvb_get_ntohl(tvb, offset+12) ^ transaction_id[1]);
900 IPv6[3] = g_htonl(tvb_get_ntohl(tvb, offset+16) ^ transaction_id[2]);
901 ti = proto_tree_add_ipv6(att_tree, stun_att_ipv6, tvb, offset+4, 16,
902 (const guint8 *)IPv6);
903 PROTO_ITEM_SET_GENERATED(ti);
910 case REQUESTED_ADDRESS_TYPE:
913 proto_tree_add_item(att_tree, stun_att_family, tvb, offset, 1, FALSE);
916 proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset+1, 3, 3);
921 proto_tree_add_item(att_tree, stun_att_reserve_next, tvb, offset, 1, FALSE);
924 case RESERVATION_TOKEN:
927 proto_tree_add_item(att_tree, stun_att_token, tvb, offset, 8, FALSE);
933 proto_tree_add_item(att_tree, stun_att_priority, tvb, offset, 4, FALSE);
937 proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset, att_length, att_length);
943 proto_tree_add_item(att_tree, stun_att_icmp_type, tvb, offset, 1, FALSE);
944 proto_tree_add_item(att_tree, stun_att_icmp_code, tvb, offset+1, 1, FALSE);
948 proto_tree_add_item(att_tree, stun_att_software, tvb, offset, att_length, FALSE);
949 if (att_length % 4 != 0)
950 proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
956 proto_tree_add_item(att_tree, stun_att_cache_timeout, tvb, offset, 4, FALSE);
962 proto_tree_add_item(att_tree, stun_att_crc32, tvb, offset, att_length, FALSE);
966 case ICE_CONTROLLING:
969 proto_tree_add_item(att_tree, stun_att_tie_breaker, tvb, offset, 8, FALSE);
973 if (att_length > 0) {
975 guint reported_len, pad=0;
976 proto_tree_add_item(att_tree, stun_att_value, tvb, offset, att_length, FALSE);
977 if (att_length % 4 != 0) {
978 pad = 4-(att_length % 4);
979 proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, pad, pad);
981 reported_len = att_length;
985 tvb_new_subset(tvb, offset,
989 if (!dissector_try_heuristic(heur_subdissector_list,
990 next_tvb, pinfo, att_tree)) {
991 call_dissector_only(data_handle,next_tvb, pinfo, att_tree);
997 case REQUESTED_TRANSPORT:
1000 proto_tree_add_item(att_tree, stun_att_transp, tvb, offset, 1, FALSE);
1005 guint8 protoCode = tvb_get_guint8(tvb, offset);
1006 proto_item_append_text(att_tree, ": %s", val_to_str(protoCode, transportnames, "Unknown (0x%8x)"));
1007 if(check_col(pinfo->cinfo,COL_INFO)) {
1009 pinfo->cinfo, COL_INFO,
1011 val_to_str(protoCode, transportnames, "Unknown (0x%8x)")
1015 proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset+1, 3, 3);
1018 case CHANNEL_NUMBER:
1021 proto_tree_add_item(att_tree, stun_att_channelnum, tvb, offset, 2, FALSE);
1023 guint16 chan = tvb_get_ntohs(tvb, offset);
1024 proto_item_append_text(att_tree, ": 0x%x", chan);
1025 if(check_col(pinfo->cinfo,COL_INFO)) {
1027 pinfo->cinfo, COL_INFO,
1028 " ChannelNumber=0x%x",
1033 proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset+2, 2, 2);
1039 proto_tree_add_item(att_tree, stun_att_bandwidth, tvb, offset, 4, FALSE);
1040 proto_item_append_text(att_tree, " %d", tvb_get_ntohl(tvb, offset));
1041 if(check_col(pinfo->cinfo,COL_INFO)) {
1043 pinfo->cinfo, COL_INFO,
1045 tvb_get_ntohl(tvb, offset)
1052 proto_tree_add_item(att_tree, stun_att_lifetime, tvb, offset, 4, FALSE);
1053 proto_item_append_text(att_tree, " %d", tvb_get_ntohl(tvb, offset));
1054 if(check_col(pinfo->cinfo,COL_INFO)) {
1056 pinfo->cinfo, COL_INFO,
1058 tvb_get_ntohl(tvb, offset)
1065 proto_tree_add_item(att_tree, stun_att_value, tvb, offset, att_length, FALSE);
1066 if (att_length % 4 != 0)
1067 proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
1070 offset += (att_length+3) & -4;
1071 msg_length -= (ATTR_HDR_LEN+att_length+3) & -4;
1075 return tvb_length(tvb);
1079 dissect_stun_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1081 return dissect_stun_message(tvb, pinfo, tree);
1085 dissect_stun_message_no_return(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1087 dissect_stun_message(tvb, pinfo, tree);
1091 dissect_stun_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1093 tcp_dissect_pdus(tvb, pinfo, tree, TRUE, MIN_HDR_LEN,
1094 get_stun_message_len, dissect_stun_message_no_return);
1098 dissect_stun_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1100 if (dissect_stun_message(tvb, pinfo, tree) == 0) {
1102 * It wasn't a valid STUN message, and wasn't
1103 * dissected as such.
1111 proto_register_stun(void)
1113 static hf_register_info hf[] = {
1116 { "Channel Number", "stun.channel", FT_UINT16,
1117 BASE_HEX, NULL, 0x0, NULL, HFILL }
1120 /* ////////////////////////////////////// */
1122 { "Message Type", "stun.type", FT_UINT16,
1123 BASE_HEX, NULL, 0, NULL, HFILL }
1125 { &hf_stun_type_class,
1126 { "Message Class", "stun.type.class", FT_UINT16,
1127 BASE_HEX, NULL, 0x0110, NULL, HFILL }
1129 { &hf_stun_type_method,
1130 { "Message Method", "stun.type.method", FT_UINT16,
1131 BASE_HEX, NULL, 0x3EEF, NULL, HFILL }
1133 { &hf_stun_type_method_assignment,
1134 { "Message Method Assignment", "stun.type.method-assignment", FT_UINT16,
1135 BASE_HEX, NULL, 0x2000, NULL, HFILL }
1138 { "Message Length", "stun.length", FT_UINT16,
1139 BASE_DEC, NULL, 0x0, NULL, HFILL }
1142 { "Message Cookie", "stun.cookie", FT_BYTES,
1143 BASE_NONE, NULL, 0x0, NULL, HFILL }
1146 { "Message Transaction ID", "stun.id", FT_BYTES,
1147 BASE_NONE, NULL, 0x0, NULL, HFILL }
1149 { &hf_stun_attributes,
1150 { "Attributes", "stun.attributes", FT_NONE,
1151 BASE_NONE, NULL, 0x0, NULL, HFILL }
1154 { "Attribute Type", "stun.attribute", FT_UINT16,
1155 BASE_HEX, NULL, 0, NULL, HFILL }
1157 { &hf_stun_response_in,
1158 { "Response In", "stun.response-in", FT_FRAMENUM,
1159 BASE_NONE, NULL, 0x0, "The response to this STUN query is in this frame", HFILL }
1161 { &hf_stun_response_to,
1162 { "Request In", "stun.response-to", FT_FRAMENUM,
1163 BASE_NONE, NULL, 0x0, "This is a response to the STUN Request in this frame", HFILL }
1166 { "Time", "stun.time", FT_RELATIVE_TIME,
1167 BASE_NONE, NULL, 0x0, "The time between the Request and the Response", HFILL }
1169 { &hf_stun_duplicate,
1170 { "Duplicated original message in", "stun.reqduplicate", FT_FRAMENUM,
1171 BASE_NONE, NULL, 0x0, "This is a duplicate of STUN message in this frame", HFILL }
1173 /* ////////////////////////////////////// */
1175 { "Attribute Type", "stun.att.type", FT_UINT16,
1176 BASE_HEX, VALS(attributes), 0x0, NULL, HFILL }
1178 { &stun_att_type_comprehension,
1179 { "Attribute Type Comprehension", "stun.att.type.comprehension", FT_UINT16,
1180 BASE_HEX, NULL, 0x8000, NULL, HFILL }
1182 { &stun_att_type_assignment,
1183 { "Attribute Type Assignment", "stun.att.type.assignment", FT_UINT16,
1184 BASE_HEX, NULL, 0x4000, NULL, HFILL }
1187 { "Attribute Length", "stun.att.length", FT_UINT16,
1188 BASE_DEC, NULL, 0x0, NULL, HFILL }
1191 { "Protocol Family", "stun.att.family", FT_UINT8,
1192 BASE_HEX, VALS(attributes_family), 0x0, NULL, HFILL }
1195 { "IP", "stun.att.ipv4", FT_IPv4,
1196 BASE_NONE, NULL, 0x0, NULL, HFILL }
1199 { "IP", "stun.att.ipv6", FT_IPv6,
1200 BASE_NONE, NULL, 0x0, NULL, HFILL }
1203 { "Port", "stun.att.port", FT_UINT16,
1204 BASE_DEC, NULL, 0x0, NULL, HFILL }
1206 { &stun_att_username,
1207 { "Username", "stun.att.username", FT_STRING,
1208 BASE_NONE, NULL, 0x0, NULL, HFILL }
1210 { &stun_att_padding,
1211 { "Padding", "stun.att.padding", FT_UINT16,
1212 BASE_DEC, NULL, 0x0, NULL, HFILL }
1215 { "HMAC-SHA1", "stun.att.hmac", FT_BYTES,
1216 BASE_NONE, NULL, 0x0, NULL, HFILL }
1219 { "CRC-32", "stun.att.crc32", FT_UINT32,
1220 BASE_HEX, NULL, 0x0, NULL, HFILL }
1222 { &stun_att_error_class,
1223 { "Error Class","stun.att.error.class", FT_UINT8,
1224 BASE_DEC, NULL, 0x07, NULL, HFILL}
1226 { &stun_att_error_number,
1227 { "Error Code","stun.att.error", FT_UINT8,
1228 BASE_DEC, NULL, 0x0, NULL, HFILL}
1230 { &stun_att_error_reason,
1231 { "Error Reason Phrase","stun.att.error.reason", FT_STRING,
1232 BASE_NONE, NULL, 0x0, NULL, HFILL}
1235 { "Realm", "stun.att.realm", FT_STRING,
1236 BASE_NONE, NULL, 0x0, NULL, HFILL }
1239 { "Nonce", "stun.att.nonce", FT_STRING,
1240 BASE_NONE, NULL, 0x0, NULL, HFILL }
1242 { &stun_att_unknown,
1243 { "Unknown Attribute","stun.att.unknown", FT_UINT16,
1244 BASE_HEX, NULL, 0x0, NULL, HFILL}
1246 { &stun_att_xor_ipv4,
1247 { "IP (XOR-d)", "stun.att.ipv4-xord", FT_BYTES,
1248 BASE_NONE, NULL, 0x0, NULL, HFILL }
1250 { &stun_att_xor_ipv6,
1251 { "IP (XOR-d)", "stun.att.ipv6-xord", FT_BYTES,
1252 BASE_NONE, NULL, 0x0, NULL, HFILL }
1254 { &stun_att_xor_port,
1255 { "Port (XOR-d)", "stun.att.port-xord", FT_BYTES,
1256 BASE_NONE, NULL, 0x0, NULL, HFILL }
1258 { &stun_att_icmp_type,
1259 { "ICMP type", "stun.att.icmp.type", FT_UINT8,
1260 BASE_DEC, NULL, 0x0, NULL, HFILL}
1262 { &stun_att_icmp_code,
1263 { "ICMP code", "stun.att.icmp.code", FT_UINT8,
1264 BASE_DEC, NULL, 0x0, NULL, HFILL}
1266 { &stun_att_software,
1267 { "Software","stun.att.software", FT_STRING,
1268 BASE_NONE, NULL, 0x0, NULL, HFILL}
1270 { &stun_att_priority,
1271 { "Priority", "stun.att.priority", FT_UINT32,
1272 BASE_DEC, NULL, 0x0, NULL, HFILL}
1274 { &stun_att_tie_breaker,
1275 { "Tie breaker", "stun.att.tie-breaker", FT_BYTES,
1276 BASE_NONE, NULL, 0x0, NULL, HFILL }
1278 { &stun_att_lifetime,
1279 { "Lifetime", "stun.att.lifetime", FT_UINT32,
1280 BASE_DEC, NULL, 0x0, NULL, HFILL}
1282 { &stun_att_change_ip,
1283 { "Change IP","stun.att.change-ip", FT_BOOLEAN,
1284 16, TFS(&tfs_set_notset), 0x0004, NULL, HFILL}
1286 { &stun_att_change_port,
1287 { "Change Port","stun.att.change-port", FT_BOOLEAN,
1288 16, TFS(&tfs_set_notset), 0x0002, NULL, HFILL}
1290 { &stun_att_reserve_next,
1291 { "Reserve next","stun.att.even-port.reserve-next", FT_UINT8,
1292 BASE_DEC, VALS(attributes_reserve_next), 0x80, NULL, HFILL}
1294 { &stun_att_cache_timeout,
1295 { "Cache timeout", "stun.att.cache-timeout", FT_UINT32,
1296 BASE_DEC, NULL, 0x0, NULL, HFILL}
1299 { "Token", "stun.att.token", FT_BYTES,
1300 BASE_NONE, NULL, 0x0, NULL, HFILL }
1303 { "Value", "stun.value", FT_BYTES,
1304 BASE_NONE, NULL, 0x0, NULL, HFILL }
1306 { &stun_att_reserved,
1307 { "Reserved", "stun.att.reserved", FT_UINT16,
1308 BASE_DEC, NULL, 0x0, NULL, HFILL }
1311 { "Transport", "stun.att.transp", FT_UINT8,
1312 BASE_HEX, VALS(transportnames), 0x0, NULL, HFILL }
1314 { &stun_att_channelnum,
1315 { "Channel-Number", "stun.att.channelnum", FT_UINT16,
1316 BASE_HEX, NULL, 0x0, NULL, HFILL }
1318 { &stun_att_bandwidth,
1319 { "Bandwidth", "stun.port.bandwidth", FT_UINT32,
1320 BASE_DEC, NULL, 0x0, NULL, HFILL }
1324 /* Setup protocol subtree array */
1325 static gint *ett[] = {
1333 /* Register the protocol name and description */
1334 proto_stun = proto_register_protocol("Session Traversal Utilities for NAT", "STUN", "stun");
1336 /* Required function calls to register the header fields and subtrees used */
1337 proto_register_field_array(proto_stun, hf, array_length(hf));
1338 proto_register_subtree_array(ett, array_length(ett));
1340 /* heuristic subdissectors (used for the DATA field) */
1341 register_heur_dissector_list("stun", &heur_subdissector_list);
1345 proto_reg_handoff_stun(void)
1347 dissector_handle_t stun_tcp_handle;
1348 dissector_handle_t stun_udp_handle;
1350 stun_tcp_handle = create_dissector_handle(dissect_stun_tcp, proto_stun);
1351 stun_udp_handle = new_create_dissector_handle(dissect_stun_udp, proto_stun);
1353 dissector_add("tcp.port", TCP_PORT_STUN, stun_tcp_handle);
1354 dissector_add("udp.port", UDP_PORT_STUN, stun_udp_handle);
1356 heur_dissector_add("udp", dissect_stun_heur, proto_stun);
1357 heur_dissector_add("tcp", dissect_stun_heur, proto_stun);
1358 heur_dissector_add("stun", dissect_stun_heur, proto_stun);
1360 data_handle = find_dissector("data");