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);
570 return tvb_length(tvb);
572 ti = proto_tree_add_item(tree, proto_stun, tvb, 0, -1, FALSE);
574 stun_tree = proto_item_add_subtree(ti, ett_stun);
577 if (msg_type_class == REQUEST) {
578 if (stun_trans->req_frame != pinfo->fd->num) {
580 it=proto_tree_add_uint(stun_tree, hf_stun_duplicate,
582 stun_trans->req_frame);
583 PROTO_ITEM_SET_GENERATED(it);
585 if (stun_trans->rep_frame) {
587 it=proto_tree_add_uint(stun_tree, hf_stun_response_in,
589 stun_trans->rep_frame);
590 PROTO_ITEM_SET_GENERATED(it);
594 /* Retransmission control */
595 if (stun_trans->rep_frame != pinfo->fd->num) {
597 it=proto_tree_add_uint(stun_tree, hf_stun_duplicate,
599 stun_trans->rep_frame);
600 PROTO_ITEM_SET_GENERATED(it);
602 if (msg_type_class == RESPONSE || msg_type_class == ERROR_RESPONSE) {
603 /* This is a response */
604 if (stun_trans->req_frame) {
608 it=proto_tree_add_uint(stun_tree, hf_stun_response_to, tvb, 0, 0,
609 stun_trans->req_frame);
610 PROTO_ITEM_SET_GENERATED(it);
612 nstime_delta(&ns, &pinfo->fd->abs_ts, &stun_trans->req_time);
613 it=proto_tree_add_time(stun_tree, hf_stun_time, tvb, 0, 0, &ns);
614 PROTO_ITEM_SET_GENERATED(it);
620 ti = proto_tree_add_uint_format(stun_tree, hf_stun_type, tvb, 0, 2,
621 msg_type, "Message Type: 0x%04x (%s %s)", msg_type, msg_method_str, msg_class_str);
622 stun_type_tree = proto_item_add_subtree(ti, ett_stun_type);
623 proto_tree_add_uint(stun_type_tree, hf_stun_type_class, tvb, 0, 2, msg_type);
624 ti = proto_tree_add_text(stun_type_tree, tvb, 0, 2, "%s (%d)", msg_class_str, msg_type_class);
625 PROTO_ITEM_SET_GENERATED(ti);
626 proto_tree_add_uint(stun_type_tree, hf_stun_type_method, tvb, 0, 2, msg_type);
627 ti = proto_tree_add_text(stun_type_tree, tvb, 0, 2, "%s (0x%03x)", msg_method_str, msg_type_method);
628 PROTO_ITEM_SET_GENERATED(ti);
629 proto_tree_add_uint(stun_type_tree, hf_stun_type_method_assignment, tvb, 0, 2, msg_type);
630 ti = proto_tree_add_text(stun_type_tree, tvb, 0, 2, "%s (%d)", match_strval((msg_type & 0x2000) >> 13, assignments), (msg_type & 0x2000) >> 13);
631 PROTO_ITEM_SET_GENERATED(ti);
633 proto_tree_add_uint(stun_tree, hf_stun_length, tvb, 2, 2, msg_length);
634 proto_tree_add_item(stun_tree, hf_stun_cookie, tvb, 4, 4, FALSE);
635 proto_tree_add_item(stun_tree, hf_stun_id, tvb, 8, 12, FALSE);
637 /* Remember this (in host order) so we can show clear xor'd addresses */
638 magic_cookie_first_word = tvb_get_ntohl(tvb, 4);
640 if (msg_length > 0) {
641 ti = proto_tree_add_item(stun_tree, hf_stun_attributes, tvb, STUN_HDR_LEN, msg_length, FALSE);
642 att_all_tree = proto_item_add_subtree(ti, ett_stun_att_all);
644 offset = STUN_HDR_LEN;
646 while (msg_length > 0) {
647 att_type = tvb_get_ntohs(tvb, offset); /* Type field in attribute header */
648 att_length = tvb_get_ntohs(tvb, offset+2); /* Length field in attribute header */
649 att_type_str = match_strval(att_type, attributes);
650 if (att_type_str == NULL)
651 att_type_str = "Unknown";
652 ti = proto_tree_add_uint_format(att_all_tree, hf_stun_attr,
653 tvb, offset, ATTR_HDR_LEN+att_length,
654 att_type, "%s", att_type_str);
655 att_tree = proto_item_add_subtree(ti, ett_stun_att);
656 ti = proto_tree_add_uint(att_tree, stun_att_type, tvb,
657 offset, 2, att_type);
658 att_type_tree = proto_item_add_subtree(ti, ett_stun_att_type);
659 proto_tree_add_uint(att_type_tree, stun_att_type_comprehension, tvb, offset, 2, att_type);
660 ti = proto_tree_add_text(att_type_tree, tvb, offset, 2,
662 match_strval((att_type & 0x8000) >> 15, comprehensions),
663 (att_type & 0x8000) >> 15);
664 PROTO_ITEM_SET_GENERATED(ti);
665 proto_tree_add_uint(att_type_tree, stun_att_type_assignment, tvb, offset, 2, att_type);
666 ti = proto_tree_add_text(att_type_tree, tvb, offset, 2,
668 match_strval((att_type & 0x4000) >> 14, assignments),
669 (att_type & 0x4000) >> 14);
670 PROTO_ITEM_SET_GENERATED(ti);
673 if (ATTR_HDR_LEN+att_length > msg_length) {
674 proto_tree_add_uint_format(att_tree,
675 stun_att_length, tvb, offset, 2,
677 "Attribute Length: %u (bogus, goes past the end of the message)",
681 proto_tree_add_uint(att_tree, stun_att_length, tvb,
682 offset, 2, att_length);
686 case ALTERNATE_SERVER:
687 case RESPONSE_ORIGIN:
691 proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset, 1, 1);
694 proto_tree_add_item(att_tree, stun_att_family, tvb, offset+1, 1, FALSE);
697 proto_tree_add_item(att_tree, stun_att_port, tvb, offset+2, 2, FALSE);
698 switch (tvb_get_guint8(tvb, offset+1)) {
702 proto_tree_add_item(att_tree, stun_att_ipv4, tvb, offset+4, 4, FALSE);
706 ip = tvb_get_ipv4(tvb,offset+4);
707 ipstr = ip_to_str((guint8*)&ip);
708 proto_item_append_text(att_tree, ": %s:%d", ipstr,tvb_get_ntohs(tvb,offset+2));
709 if(check_col(pinfo->cinfo,COL_INFO)) {
711 pinfo->cinfo, COL_INFO,
713 val_to_str(att_type, attributes, "Unknown"),
715 tvb_get_ntohs(tvb,offset+2)
724 proto_tree_add_item(att_tree, stun_att_ipv6, tvb, offset+4, 16, FALSE);
732 proto_tree_add_item(att_tree, stun_att_change_ip, tvb, offset, 4, FALSE);
733 proto_tree_add_item(att_tree, stun_att_change_port, tvb, offset, 4, FALSE);
737 proto_tree_add_item(att_tree, stun_att_username, tvb, offset, att_length, FALSE);
738 proto_item_append_text(att_tree, ": %s", tvb_get_ephemeral_string(tvb, offset, att_length));
739 if(check_col(pinfo->cinfo,COL_INFO)) {
741 pinfo->cinfo, COL_INFO,
743 tvb_get_ephemeral_string(tvb,offset, att_length)
746 if (att_length % 4 != 0)
747 proto_tree_add_uint(att_tree, stun_att_padding,
748 tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
751 case MESSAGE_INTEGRITY:
754 proto_tree_add_item(att_tree, stun_att_hmac, tvb, offset, att_length, FALSE);
760 proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset, 2, 2);
763 proto_tree_add_item(att_tree, stun_att_error_class, tvb, offset+2, 1, FALSE);
766 proto_tree_add_item(att_tree, stun_att_error_number, tvb, offset+3, 1, FALSE);
768 int human_error_num = tvb_get_guint8(tvb, offset+2) * 100 + tvb_get_guint8(tvb, offset+3);
769 proto_item_append_text(
772 human_error_num, /* human readable error code */
773 val_to_str(human_error_num, error_code, "*Unknown error code*")
775 if(check_col(pinfo->cinfo,COL_INFO)) {
777 pinfo->cinfo, COL_INFO,
778 " error-code: %d (%s)",
780 val_to_str(human_error_num, error_code, "*Unknown error code*")
786 proto_tree_add_item(att_tree, stun_att_error_reason, tvb, offset+4, att_length-4, FALSE);
788 proto_item_append_text(att_tree, ": %s", tvb_get_ephemeral_string(tvb, offset+4, att_length-4));
789 if(check_col(pinfo->cinfo,COL_INFO)) {
791 pinfo->cinfo, COL_INFO,
793 tvb_get_ephemeral_string(tvb, offset+4, att_length-4)
797 if (att_length % 4 != 0)
798 proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
801 case UNKNOWN_ATTRIBUTES:
802 for (i = 0; i < att_length; i += 2)
803 proto_tree_add_item(att_tree, stun_att_unknown, tvb, offset+i, 2, FALSE);
804 if (att_length % 4 != 0)
805 proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
809 proto_tree_add_item(att_tree, stun_att_realm, tvb, offset, att_length, FALSE);
810 proto_item_append_text(att_tree, ": %s", tvb_get_ephemeral_string(tvb, offset, att_length));
811 if(check_col(pinfo->cinfo,COL_INFO)) {
813 pinfo->cinfo, COL_INFO,
815 tvb_get_ephemeral_string(tvb,offset, att_length)
818 if (att_length % 4 != 0)
819 proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
823 proto_tree_add_item(att_tree, stun_att_nonce, tvb, offset, att_length, FALSE);
824 proto_item_append_text(att_tree, ": %s", tvb_get_ephemeral_string(tvb, offset, att_length));
825 if(check_col(pinfo->cinfo,COL_INFO)) {
827 pinfo->cinfo, COL_INFO,
831 if (att_length % 4 != 0)
832 proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
835 case XOR_MAPPED_ADDRESS:
836 case XOR_PEER_ADDRESS:
837 case XOR_RELAYED_ADDRESS:
838 case XOR_RESPONSE_TARGET:
839 case XOR_REFLECTED_FROM:
842 proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset, 1, 1);
845 proto_tree_add_item(att_tree, stun_att_family, tvb, offset+1, 1, FALSE);
848 proto_tree_add_item(att_tree, stun_att_xor_port, tvb, offset+2, 2, FALSE);
850 /* Show the port 'in the clear'
851 XOR (host order) transid with (host order) xor-port.
852 Add host-order port into tree. */
853 ti = proto_tree_add_uint(att_tree, stun_att_port, tvb, offset+2, 2,
854 tvb_get_ntohs(tvb, offset+2) ^
855 (magic_cookie_first_word >> 16));
856 PROTO_ITEM_SET_GENERATED(ti);
860 switch (tvb_get_guint8(tvb, offset+1)) {
864 proto_tree_add_item(att_tree, stun_att_xor_ipv4, tvb, offset+4, 4, FALSE);
866 /* Show the address 'in the clear'.
867 XOR (host order) transid with (host order) xor-address.
868 Add in network order tree. */
869 ti = proto_tree_add_ipv4(att_tree, stun_att_ipv4, tvb, offset+4, 4,
870 g_htonl(tvb_get_ntohl(tvb, offset+4) ^
871 magic_cookie_first_word));
872 PROTO_ITEM_SET_GENERATED(ti);
878 ip = g_htonl(tvb_get_ntohl(tvb, offset+4) ^ magic_cookie_first_word);
879 ipstr = ip_to_str((guint8*)&ip);
880 port = tvb_get_ntohs(tvb, offset+2) ^ (magic_cookie_first_word >> 16);
881 proto_item_append_text(att_tree, ": %s:%d", ipstr, port);
882 if(check_col(pinfo->cinfo,COL_INFO)) {
884 pinfo->cinfo, COL_INFO,
886 val_to_str(att_type, attributes, "Unknown"),
897 proto_tree_add_item(att_tree, stun_att_xor_ipv6, tvb, offset+4, 16, FALSE);
900 IPv6[0] = g_htonl(tvb_get_ntohl(tvb, offset+4) ^ magic_cookie_first_word);
901 IPv6[1] = g_htonl(tvb_get_ntohl(tvb, offset+8) ^ transaction_id[0]);
902 IPv6[2] = g_htonl(tvb_get_ntohl(tvb, offset+12) ^ transaction_id[1]);
903 IPv6[3] = g_htonl(tvb_get_ntohl(tvb, offset+16) ^ transaction_id[2]);
904 ti = proto_tree_add_ipv6(att_tree, stun_att_ipv6, tvb, offset+4, 16,
905 (const guint8 *)IPv6);
906 PROTO_ITEM_SET_GENERATED(ti);
913 case REQUESTED_ADDRESS_TYPE:
916 proto_tree_add_item(att_tree, stun_att_family, tvb, offset, 1, FALSE);
919 proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset+1, 3, 3);
924 proto_tree_add_item(att_tree, stun_att_reserve_next, tvb, offset, 1, FALSE);
927 case RESERVATION_TOKEN:
930 proto_tree_add_item(att_tree, stun_att_token, tvb, offset, 8, FALSE);
936 proto_tree_add_item(att_tree, stun_att_priority, tvb, offset, 4, FALSE);
940 proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset, att_length, att_length);
946 proto_tree_add_item(att_tree, stun_att_icmp_type, tvb, offset, 1, FALSE);
947 proto_tree_add_item(att_tree, stun_att_icmp_code, tvb, offset+1, 1, FALSE);
951 proto_tree_add_item(att_tree, stun_att_software, tvb, offset, att_length, FALSE);
952 if (att_length % 4 != 0)
953 proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
959 proto_tree_add_item(att_tree, stun_att_cache_timeout, tvb, offset, 4, FALSE);
965 proto_tree_add_item(att_tree, stun_att_crc32, tvb, offset, att_length, FALSE);
969 case ICE_CONTROLLING:
972 proto_tree_add_item(att_tree, stun_att_tie_breaker, tvb, offset, 8, FALSE);
976 if (att_length > 0) {
978 guint reported_len, pad=0;
979 proto_tree_add_item(att_tree, stun_att_value, tvb, offset, att_length, FALSE);
980 if (att_length % 4 != 0) {
981 pad = 4-(att_length % 4);
982 proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, pad, pad);
984 reported_len = att_length;
988 tvb_new_subset(tvb, offset,
992 if (!dissector_try_heuristic(heur_subdissector_list,
993 next_tvb, pinfo, att_tree)) {
994 call_dissector_only(data_handle,next_tvb, pinfo, att_tree);
1000 case REQUESTED_TRANSPORT:
1003 proto_tree_add_item(att_tree, stun_att_transp, tvb, offset, 1, FALSE);
1008 guint8 protoCode = tvb_get_guint8(tvb, offset);
1009 proto_item_append_text(att_tree, ": %s", val_to_str(protoCode, transportnames, "Unknown (0x%8x)"));
1010 if(check_col(pinfo->cinfo,COL_INFO)) {
1012 pinfo->cinfo, COL_INFO,
1014 val_to_str(protoCode, transportnames, "Unknown (0x%8x)")
1018 proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset+1, 3, 3);
1021 case CHANNEL_NUMBER:
1024 proto_tree_add_item(att_tree, stun_att_channelnum, tvb, offset, 2, FALSE);
1026 guint16 chan = tvb_get_ntohs(tvb, offset);
1027 proto_item_append_text(att_tree, ": 0x%x", chan);
1028 if(check_col(pinfo->cinfo,COL_INFO)) {
1030 pinfo->cinfo, COL_INFO,
1031 " ChannelNumber=0x%x",
1036 proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset+2, 2, 2);
1042 proto_tree_add_item(att_tree, stun_att_bandwidth, tvb, offset, 4, FALSE);
1043 proto_item_append_text(att_tree, " %d", tvb_get_ntohl(tvb, offset));
1044 if(check_col(pinfo->cinfo,COL_INFO)) {
1046 pinfo->cinfo, COL_INFO,
1048 tvb_get_ntohl(tvb, offset)
1055 proto_tree_add_item(att_tree, stun_att_lifetime, tvb, offset, 4, FALSE);
1056 proto_item_append_text(att_tree, " %d", tvb_get_ntohl(tvb, offset));
1057 if(check_col(pinfo->cinfo,COL_INFO)) {
1059 pinfo->cinfo, COL_INFO,
1061 tvb_get_ntohl(tvb, offset)
1068 proto_tree_add_item(att_tree, stun_att_value, tvb, offset, att_length, FALSE);
1069 if (att_length % 4 != 0)
1070 proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
1073 offset += (att_length+3) & -4;
1074 msg_length -= (ATTR_HDR_LEN+att_length+3) & -4;
1078 return tvb_length(tvb);
1082 dissect_stun_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1084 return dissect_stun_message(tvb, pinfo, tree);
1088 dissect_stun_message_no_return(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1090 dissect_stun_message(tvb, pinfo, tree);
1094 dissect_stun_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1096 tcp_dissect_pdus(tvb, pinfo, tree, TRUE, MIN_HDR_LEN,
1097 get_stun_message_len, dissect_stun_message_no_return);
1101 dissect_stun_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1103 if (dissect_stun_message(tvb, pinfo, tree) == 0) {
1105 * It wasn't a valid STUN message, and wasn't
1106 * dissected as such.
1114 proto_register_stun(void)
1116 static hf_register_info hf[] = {
1119 { "Channel Number", "stun.channel", FT_UINT16,
1120 BASE_HEX, NULL, 0x0, NULL, HFILL }
1123 /* ////////////////////////////////////// */
1125 { "Message Type", "stun.type", FT_UINT16,
1126 BASE_HEX, NULL, 0, NULL, HFILL }
1128 { &hf_stun_type_class,
1129 { "Message Class", "stun.type.class", FT_UINT16,
1130 BASE_HEX, NULL, 0x0110, NULL, HFILL }
1132 { &hf_stun_type_method,
1133 { "Message Method", "stun.type.method", FT_UINT16,
1134 BASE_HEX, NULL, 0x3EEF, NULL, HFILL }
1136 { &hf_stun_type_method_assignment,
1137 { "Message Method Assignment", "stun.type.method-assignment", FT_UINT16,
1138 BASE_HEX, NULL, 0x2000, NULL, HFILL }
1141 { "Message Length", "stun.length", FT_UINT16,
1142 BASE_DEC, NULL, 0x0, NULL, HFILL }
1145 { "Message Cookie", "stun.cookie", FT_BYTES,
1146 BASE_NONE, NULL, 0x0, NULL, HFILL }
1149 { "Message Transaction ID", "stun.id", FT_BYTES,
1150 BASE_NONE, NULL, 0x0, NULL, HFILL }
1152 { &hf_stun_attributes,
1153 { "Attributes", "stun.attributes", FT_NONE,
1154 BASE_NONE, NULL, 0x0, NULL, HFILL }
1157 { "Attribute Type", "stun.attribute", FT_UINT16,
1158 BASE_HEX, NULL, 0, NULL, HFILL }
1160 { &hf_stun_response_in,
1161 { "Response In", "stun.response-in", FT_FRAMENUM,
1162 BASE_NONE, NULL, 0x0, "The response to this STUN query is in this frame", HFILL }
1164 { &hf_stun_response_to,
1165 { "Request In", "stun.response-to", FT_FRAMENUM,
1166 BASE_NONE, NULL, 0x0, "This is a response to the STUN Request in this frame", HFILL }
1169 { "Time", "stun.time", FT_RELATIVE_TIME,
1170 BASE_NONE, NULL, 0x0, "The time between the Request and the Response", HFILL }
1172 { &hf_stun_duplicate,
1173 { "Duplicated original message in", "stun.reqduplicate", FT_FRAMENUM,
1174 BASE_NONE, NULL, 0x0, "This is a duplicate of STUN message in this frame", HFILL }
1176 /* ////////////////////////////////////// */
1178 { "Attribute Type", "stun.att.type", FT_UINT16,
1179 BASE_HEX, VALS(attributes), 0x0, NULL, HFILL }
1181 { &stun_att_type_comprehension,
1182 { "Attribute Type Comprehension", "stun.att.type.comprehension", FT_UINT16,
1183 BASE_HEX, NULL, 0x8000, NULL, HFILL }
1185 { &stun_att_type_assignment,
1186 { "Attribute Type Assignment", "stun.att.type.assignment", FT_UINT16,
1187 BASE_HEX, NULL, 0x4000, NULL, HFILL }
1190 { "Attribute Length", "stun.att.length", FT_UINT16,
1191 BASE_DEC, NULL, 0x0, NULL, HFILL }
1194 { "Protocol Family", "stun.att.family", FT_UINT8,
1195 BASE_HEX, VALS(attributes_family), 0x0, NULL, HFILL }
1198 { "IP", "stun.att.ipv4", FT_IPv4,
1199 BASE_NONE, NULL, 0x0, NULL, HFILL }
1202 { "IP", "stun.att.ipv6", FT_IPv6,
1203 BASE_NONE, NULL, 0x0, NULL, HFILL }
1206 { "Port", "stun.att.port", FT_UINT16,
1207 BASE_DEC, NULL, 0x0, NULL, HFILL }
1209 { &stun_att_username,
1210 { "Username", "stun.att.username", FT_STRING,
1211 BASE_NONE, NULL, 0x0, NULL, HFILL }
1213 { &stun_att_padding,
1214 { "Padding", "stun.att.padding", FT_UINT16,
1215 BASE_DEC, NULL, 0x0, NULL, HFILL }
1218 { "HMAC-SHA1", "stun.att.hmac", FT_BYTES,
1219 BASE_NONE, NULL, 0x0, NULL, HFILL }
1222 { "CRC-32", "stun.att.crc32", FT_UINT32,
1223 BASE_HEX, NULL, 0x0, NULL, HFILL }
1225 { &stun_att_error_class,
1226 { "Error Class","stun.att.error.class", FT_UINT8,
1227 BASE_DEC, NULL, 0x07, NULL, HFILL}
1229 { &stun_att_error_number,
1230 { "Error Code","stun.att.error", FT_UINT8,
1231 BASE_DEC, NULL, 0x0, NULL, HFILL}
1233 { &stun_att_error_reason,
1234 { "Error Reason Phrase","stun.att.error.reason", FT_STRING,
1235 BASE_NONE, NULL, 0x0, NULL, HFILL}
1238 { "Realm", "stun.att.realm", FT_STRING,
1239 BASE_NONE, NULL, 0x0, NULL, HFILL }
1242 { "Nonce", "stun.att.nonce", FT_STRING,
1243 BASE_NONE, NULL, 0x0, NULL, HFILL }
1245 { &stun_att_unknown,
1246 { "Unknown Attribute","stun.att.unknown", FT_UINT16,
1247 BASE_HEX, NULL, 0x0, NULL, HFILL}
1249 { &stun_att_xor_ipv4,
1250 { "IP (XOR-d)", "stun.att.ipv4-xord", FT_BYTES,
1251 BASE_NONE, NULL, 0x0, NULL, HFILL }
1253 { &stun_att_xor_ipv6,
1254 { "IP (XOR-d)", "stun.att.ipv6-xord", FT_BYTES,
1255 BASE_NONE, NULL, 0x0, NULL, HFILL }
1257 { &stun_att_xor_port,
1258 { "Port (XOR-d)", "stun.att.port-xord", FT_BYTES,
1259 BASE_NONE, NULL, 0x0, NULL, HFILL }
1261 { &stun_att_icmp_type,
1262 { "ICMP type", "stun.att.icmp.type", FT_UINT8,
1263 BASE_DEC, NULL, 0x0, NULL, HFILL}
1265 { &stun_att_icmp_code,
1266 { "ICMP code", "stun.att.icmp.code", FT_UINT8,
1267 BASE_DEC, NULL, 0x0, NULL, HFILL}
1269 { &stun_att_software,
1270 { "Software","stun.att.software", FT_STRING,
1271 BASE_NONE, NULL, 0x0, NULL, HFILL}
1273 { &stun_att_priority,
1274 { "Priority", "stun.att.priority", FT_UINT32,
1275 BASE_DEC, NULL, 0x0, NULL, HFILL}
1277 { &stun_att_tie_breaker,
1278 { "Tie breaker", "stun.att.tie-breaker", FT_BYTES,
1279 BASE_NONE, NULL, 0x0, NULL, HFILL }
1281 { &stun_att_lifetime,
1282 { "Lifetime", "stun.att.lifetime", FT_UINT32,
1283 BASE_DEC, NULL, 0x0, NULL, HFILL}
1285 { &stun_att_change_ip,
1286 { "Change IP","stun.att.change-ip", FT_BOOLEAN,
1287 16, TFS(&tfs_set_notset), 0x0004, NULL, HFILL}
1289 { &stun_att_change_port,
1290 { "Change Port","stun.att.change-port", FT_BOOLEAN,
1291 16, TFS(&tfs_set_notset), 0x0002, NULL, HFILL}
1293 { &stun_att_reserve_next,
1294 { "Reserve next","stun.att.even-port.reserve-next", FT_UINT8,
1295 BASE_DEC, VALS(attributes_reserve_next), 0x80, NULL, HFILL}
1297 { &stun_att_cache_timeout,
1298 { "Cache timeout", "stun.att.cache-timeout", FT_UINT32,
1299 BASE_DEC, NULL, 0x0, NULL, HFILL}
1302 { "Token", "stun.att.token", FT_BYTES,
1303 BASE_NONE, NULL, 0x0, NULL, HFILL }
1306 { "Value", "stun.value", FT_BYTES,
1307 BASE_NONE, NULL, 0x0, NULL, HFILL }
1309 { &stun_att_reserved,
1310 { "Reserved", "stun.att.reserved", FT_UINT16,
1311 BASE_DEC, NULL, 0x0, NULL, HFILL }
1314 { "Transport", "stun.att.transp", FT_UINT8,
1315 BASE_HEX, VALS(transportnames), 0x0, NULL, HFILL }
1317 { &stun_att_channelnum,
1318 { "Channel-Number", "stun.att.channelnum", FT_UINT16,
1319 BASE_HEX, NULL, 0x0, NULL, HFILL }
1321 { &stun_att_bandwidth,
1322 { "Bandwidth", "stun.port.bandwidth", FT_UINT32,
1323 BASE_DEC, NULL, 0x0, NULL, HFILL }
1327 /* Setup protocol subtree array */
1328 static gint *ett[] = {
1336 /* Register the protocol name and description */
1337 proto_stun = proto_register_protocol("Session Traversal Utilities for NAT", "STUN", "stun");
1339 /* Required function calls to register the header fields and subtrees used */
1340 proto_register_field_array(proto_stun, hf, array_length(hf));
1341 proto_register_subtree_array(ett, array_length(ett));
1343 /* heuristic subdissectors (used for the DATA field) */
1344 register_heur_dissector_list("stun", &heur_subdissector_list);
1348 proto_reg_handoff_stun(void)
1350 dissector_handle_t stun_tcp_handle;
1351 dissector_handle_t stun_udp_handle;
1353 stun_tcp_handle = create_dissector_handle(dissect_stun_tcp, proto_stun);
1354 stun_udp_handle = new_create_dissector_handle(dissect_stun_udp, proto_stun);
1356 dissector_add("tcp.port", TCP_PORT_STUN, stun_tcp_handle);
1357 dissector_add("udp.port", UDP_PORT_STUN, stun_udp_handle);
1359 heur_dissector_add("udp", dissect_stun_heur, proto_stun);
1360 heur_dissector_add("tcp", dissect_stun_heur, proto_stun);
1361 heur_dissector_add("stun", dissect_stun_heur, proto_stun);
1363 data_handle = find_dissector("data");