Upon 2nd thought: revert changes I made to remove 'if(checkcol(...)' around col_add_f...
[obnox/wireshark/wip.git] / epan / dissectors / packet-stun.c
1 /* packet-stun.c
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>
7  *
8  * $Id$
9  *
10  * Wireshark - Network traffic analyzer
11  * By Gerald Combs <gerald@wireshark.org>
12  * Copyright 1998 Gerald Combs
13  *
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.
18  *
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.
23  *
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.
27  *
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
34  */
35
36 #ifdef HAVE_CONFIG_H
37 # include "config.h"
38 #endif
39
40 #include <glib.h>
41
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>
47
48 /* heuristic subdissectors */
49 static heur_dissector_list_t heur_subdissector_list;
50
51 /* data dissector handle */
52 static dissector_handle_t data_handle;
53
54 /* Initialize the protocol and registered fields */
55 static int proto_stun = -1;
56
57 static int hf_stun_channel = -1;
58
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;
72
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;
110
111
112 /* Structure containing transaction specific information */
113 typedef struct _stun_transaction_t {
114         guint32 req_frame;
115         guint32 rep_frame;
116         nstime_t req_time;
117 } stun_transaction_t;
118
119 /* Structure containing conversation specific information */
120 typedef struct _stun_conv_info_t {
121         emem_tree_t *transaction_pdus;
122 } stun_conv_info_t;
123
124
125 /* Message classes */
126 #define REQUEST         0x0000
127 #define INDICATION      0x0001
128 #define RESPONSE        0x0002
129 #define ERROR_RESPONSE  0x0003
130
131
132 /* Methods */
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 */
138 /* Indications */
139 #define SEND                    0x0006  /* draft-ietf-behave-turn-10*/
140 #define DATA_IND                0x0007  /* draft-ietf-behave-turn-10*/
141
142
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 */
180  
181 /* divers */
182 #define PROTO_NUM_UDP   17
183 #define PROTO_NUM_TCP   6
184 #define PROTO_NUM_ERR   255
185
186 #define TURN_REQUESTED_PROPS_EVEN_PORT          0x01
187 #define TURN_REQUESTED_PROPS_PAIR_OF_PORTS      0x02
188
189 #define TURN_CHANNEL_NUMBER_MIN                 0x4000
190 #define TURN_CHANNEL_NUMBER_MAX                 0xFFFE
191
192
193
194
195
196
197
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;
204
205 #define UDP_PORT_STUN   3478
206 #define TCP_PORT_STUN   3478
207
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
212
213 static const value_string transportnames[] = {
214         { 17, "UDP" },
215         {  6, "TCP" },
216         {  0, NULL }
217 };
218
219 static const value_string classes[] = {
220         {REQUEST       , "Request"},
221         {INDICATION    , "Indication"},
222         {RESPONSE      , "Success Response"},
223         {ERROR_RESPONSE, "Error Response"},
224         {0x00          , NULL}
225 };
226
227 static const value_string methods[] = {
228         {BINDING          , "Binding"},
229         {ALLOCATE         , "Allocate"},
230         {REFRESH          , "Refresh"},
231         {CHANNELBIND      , "Channel-Bind"},
232         {SEND             , "Send"},
233         {DATA_IND         , "Data"},
234         {CREATE_PERMISSION, "CreatePermission"},
235         {0x00             , NULL}
236 };
237
238
239
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"},
251         {DATA                  , "DATA"},
252         {REALM                 , "REALM"},
253         {NONCE                 , "NONCE"},
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"},
266         {ICMP                  , "ICMP"},
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"},
275         {0x00                  , NULL}
276 };
277
278 static const value_string assignments[] = {
279         {0x0000, "IETF Review"},
280         {0x0001, "Designated Expert"},
281         {0x00, NULL}
282 };
283
284 static const value_string comprehensions[] = {
285         {0x0000, "Required"},
286         {0x0001, "Optional"},
287         {0x00  , NULL}
288 };
289
290 static const value_string attributes_reserve_next[] = {
291         {0, "No reservation"},
292         {1, "Reserve next port number"},
293         {0x00, NULL}
294 };
295
296 static const value_string attributes_properties_p[] = {
297         {0, "All allocation"},
298         {1, "Preserving allocation"},
299         {0x00, NULL}
300 };
301
302 static const value_string attributes_family[] = {
303         {0x0001, "IPv4"},
304         {0x0002, "IPv6"},
305         {0x00, NULL}
306 };
307
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"},
325         {0x00, NULL}
326 };
327
328
329 static guint
330 get_stun_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
331 {
332         guint16 type = tvb_get_ntohs(tvb, offset);
333         guint16 length = tvb_get_ntohs(tvb, offset+2);
334         guint res;
335
336         if (type & 0xC000)
337         {
338                 /* two first bits not NULL => should be a channel-data message */
339                 res = (guint) ((length + CHANNEL_DATA_HDR_LEN +3) & -4);
340         }
341         else
342         {
343                 /* Normal STUN message */
344                 res = (guint) length + STUN_HDR_LEN;
345         }
346         return res;
347 }
348
349 static int
350 dissect_stun_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
351 {
352         proto_item *ti;
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;
358         guint16 msg_type;
359         guint16 msg_length;
360         guint16 msg_type_method;
361         guint16 msg_type_class;
362         const char *msg_class_str;
363         const char *msg_method_str;
364         guint16 att_type;
365         guint16 att_length;
366         const char *att_type_str;
367         guint16 offset;
368         guint i;
369         guint magic_cookie_first_word;
370         guint len;
371         guint msg_total_len;
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];
377
378         /*
379          * First check if the frame is really meant for us.
380          */
381
382         offset = 0;
383         len = tvb_length(tvb);
384
385
386
387         /* First, make sure we have enough data to do the check. */
388         if (len < MIN_HDR_LEN)
389                 return 0;
390
391         msg_type = tvb_get_ntohs(tvb, 0);
392         msg_length = tvb_get_ntohs(tvb, 2);
393
394         if (msg_type & 0xC000)
395         {
396                 /* two first bits not NULL => should be a channel-data message */
397                 if (msg_type == 0xFFFF)
398                         return 0;
399                 /* note that padding is only mandatory over streaming 
400                    protocols */
401                 msg_total_len = (guint) ((msg_length + CHANNEL_DATA_HDR_LEN +3) & -4) ;
402
403                 /* check if payload enough */
404                 if (len != msg_total_len) {
405                         if (pinfo->ipproto != IP_PROTO_UDP) {
406                                 return 0;
407                         }
408                         /* recalculate the total length without padding */
409                         msg_total_len = (guint) msg_length + CHANNEL_DATA_HDR_LEN;
410                         if (len != msg_total_len) 
411                                 return 0;
412                 }
413         }
414         else 
415         {
416                 /* Normal STUN message */
417                 msg_total_len = (guint) msg_length + STUN_HDR_LEN;
418                 if (len < STUN_HDR_LEN)
419                         return 0;
420                 /* Check if it is really a STUN message */
421                 if ( tvb_get_ntohl(tvb, 4) != 0x2112a442)
422                         return 0;
423
424                 /* check if payload enough */
425                 if (len != msg_total_len)
426                         return 0;
427         }
428
429         /* The message seems to be a valid STUN message! */
430
431         col_set_str(pinfo->cinfo, COL_PROTOCOL, "STUN");
432
433         /* BEGIN of CHANNEL-DATA specific section */
434         if (msg_type & 0xC000)
435         {
436                 guint data_length;
437                 tvbuff_t *next_tvb;
438                 guint reported_len, new_len;
439                 /* two first bits not NULL => should be a channel-data message*/
440
441                 /* Clear out stuff in the info column */
442                 col_set_str(pinfo->cinfo, COL_INFO, "ChannelData TURN Message");
443
444                 if (!tree)
445                         return tvb_length(tvb);
446                 ti = proto_tree_add_item(
447                         tree, proto_stun, tvb, 0, 
448                         CHANNEL_DATA_HDR_LEN, 
449                         FALSE);
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;
455
456
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;
462                 }
463                 next_tvb = tvb_new_subset(tvb, CHANNEL_DATA_HDR_LEN, new_len, 
464                                           reported_len);
465
466
467                 if (!dissector_try_heuristic(heur_subdissector_list, 
468                                              next_tvb, pinfo, tree)) {
469                         call_dissector_only(data_handle,next_tvb, pinfo, tree);
470                 }
471
472                 return tvb_length(tvb);
473         }
474         /* END of CHANNEL-DATA specific section */
475
476         /* At this stage, we know this is a standard stun message */
477
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);
483
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;
488
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);
491
492         /* Do we already have a conversation ? */
493         conversation = 
494                 find_conversation(pinfo->fd->num, 
495                                   &pinfo->src, &pinfo->dst,
496                                   pinfo->ptype, 
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,
502                                                 pinfo->ptype,
503                                                 pinfo->srcport, pinfo->destport, 0);
504         }
505         /*
506          * Do we already have a state structure for this conv
507          */
508         stun_info = conversation_get_proto_data(conversation, proto_stun);
509         if (!stun_info) {
510                 /* No.  Attach that information to the conversation, and add
511                  * it to the list of information structures.
512                  */
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);
516         }
517
518         if (!pinfo->fd->flags.visited) {
519                 if ((stun_trans =
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, 
527                                                transaction_id_key, 
528                                                (void *)stun_trans);
529                 }
530           
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;
535                         }
536   
537                 } else {
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;
541                         }
542          
543                 }
544         } else {
545                 stun_trans=se_tree_lookup32_array(stun_info->transaction_pdus, 
546                                                   transaction_id_key);
547         }
548         
549         if (!stun_trans) {
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;
555         }
556
557
558         msg_class_str = match_strval(msg_type_class, classes);
559         msg_method_str = match_strval(msg_type_method, methods);
560
561         if (msg_method_str == NULL)
562                 msg_method_str = "Unknown";
563
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);
567         }
568
569         if (!tree)
570                 return tvb_length(tvb);
571
572         ti = proto_tree_add_item(tree, proto_stun, tvb, 0, -1, FALSE);
573
574         stun_tree = proto_item_add_subtree(ti, ett_stun);
575
576
577         if (msg_type_class == REQUEST) {
578                 if (stun_trans->req_frame != pinfo->fd->num) {
579                         proto_item *it;
580                         it=proto_tree_add_uint(stun_tree, hf_stun_duplicate, 
581                                                tvb, 0, 0, 
582                                                stun_trans->req_frame);
583                         PROTO_ITEM_SET_GENERATED(it);
584                 }
585                 if (stun_trans->rep_frame) {
586                         proto_item *it;
587                         it=proto_tree_add_uint(stun_tree, hf_stun_response_in, 
588                                                tvb, 0, 0, 
589                                                stun_trans->rep_frame);
590                         PROTO_ITEM_SET_GENERATED(it);
591                 }
592         }
593         else {
594                 /* Retransmission control */
595                 if (stun_trans->rep_frame != pinfo->fd->num) {
596                         proto_item *it;
597                         it=proto_tree_add_uint(stun_tree, hf_stun_duplicate, 
598                                                tvb, 0, 0, 
599                                                stun_trans->rep_frame);
600                         PROTO_ITEM_SET_GENERATED(it);
601                 }
602                 if (msg_type_class == RESPONSE || msg_type_class == ERROR_RESPONSE) {
603                         /* This is a response */
604                         if (stun_trans->req_frame) {
605                                 proto_item *it;
606                                 nstime_t ns;
607
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);
611
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);
615                         }
616     
617                 }
618         }
619
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);
632
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);
636
637         /* Remember this (in host order) so we can show clear xor'd addresses */
638         magic_cookie_first_word = tvb_get_ntohl(tvb, 4);
639
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);
643
644                 offset = STUN_HDR_LEN;
645
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,
661                                                  "%s (%d)",
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,
667                                                  "%s (%d)",
668                                                  match_strval((att_type & 0x4000) >> 14, assignments),
669                                                  (att_type & 0x4000) >> 14);
670                         PROTO_ITEM_SET_GENERATED(ti);
671
672                         offset += 2;
673                         if (ATTR_HDR_LEN+att_length > msg_length) {
674                                 proto_tree_add_uint_format(att_tree,
675                                                            stun_att_length, tvb, offset, 2,
676                                                            att_length,
677                                                            "Attribute Length: %u (bogus, goes past the end of the message)",
678                                                            att_length);
679                                 break;
680                         }
681                         proto_tree_add_uint(att_tree, stun_att_length, tvb,
682                                             offset, 2, att_length);
683                         offset += 2;
684                         switch (att_type) {
685                         case MAPPED_ADDRESS:
686                         case ALTERNATE_SERVER:
687                         case RESPONSE_ORIGIN:
688                         case OTHER_ADDRESS:
689                                 if (att_length < 1)
690                                         break;
691                                 proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset, 1, 1);
692                                 if (att_length < 2)
693                                         break;
694                                 proto_tree_add_item(att_tree, stun_att_family, tvb, offset+1, 1, FALSE);
695                                 if (att_length < 4)
696                                         break;
697                                 proto_tree_add_item(att_tree, stun_att_port, tvb, offset+2, 2, FALSE);
698                                 switch (tvb_get_guint8(tvb, offset+1)) {
699                                 case 1:
700                                         if (att_length < 8)
701                                                 break;
702                                         proto_tree_add_item(att_tree, stun_att_ipv4, tvb, offset+4, 4, FALSE);
703                                         {
704                                                 const gchar *ipstr;
705                                                 guint32 ip;
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)) {
710                                                         col_append_fstr(
711                                                                 pinfo->cinfo, COL_INFO,
712                                                                 " %s: %s:%d",
713                                                                 val_to_str(att_type, attributes, "Unknown"),
714                                                                 ipstr,
715                                                                 tvb_get_ntohs(tvb,offset+2)
716                                                                 );
717                                                 }
718                                         }
719                                         break;
720
721                                 case 2:
722                                         if (att_length < 20)
723                                                 break;
724                                         proto_tree_add_item(att_tree, stun_att_ipv6, tvb, offset+4, 16, FALSE);
725                                         break;
726                                 }
727                                 break;
728
729                         case CHANGE_REQUEST:
730                                 if (att_length < 4)
731                                         break;
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);
734                                 break;
735
736                         case USERNAME:
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)) {
740                                         col_append_fstr(
741                                                 pinfo->cinfo, COL_INFO,
742                                                 " user: %s",
743                                                 tvb_get_ephemeral_string(tvb,offset, att_length)
744                                                 );
745                                 }
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));
749                                 break;
750
751                         case MESSAGE_INTEGRITY:
752                                 if (att_length < 20)
753                                         break;
754                                 proto_tree_add_item(att_tree, stun_att_hmac, tvb, offset, att_length, FALSE);
755                                 break;
756
757                         case ERROR_CODE:
758                                 if (att_length < 2)
759                                         break;
760                                 proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset, 2, 2);
761                                 if (att_length < 3)
762                                         break;
763                                 proto_tree_add_item(att_tree, stun_att_error_class, tvb, offset+2, 1, FALSE);
764                                 if (att_length < 4)
765                                         break;
766                                 proto_tree_add_item(att_tree, stun_att_error_number, tvb, offset+3, 1, FALSE);
767                                 {
768                                         int human_error_num = tvb_get_guint8(tvb, offset+2) * 100 + tvb_get_guint8(tvb, offset+3);
769                                         proto_item_append_text(
770                                                 att_tree,
771                                                 " %d (%s)",
772                                                 human_error_num, /* human readable error code */
773                                                 val_to_str(human_error_num, error_code, "*Unknown error code*")
774                                                 );
775                                         if(check_col(pinfo->cinfo,COL_INFO)) {
776                                                 col_append_fstr(
777                                                         pinfo->cinfo, COL_INFO,
778                                                         " error-code: %d (%s)",
779                                                         human_error_num,
780                                                         val_to_str(human_error_num, error_code, "*Unknown error code*")
781                                                         );
782                                         }
783                                 }
784                                 if (att_length < 5)
785                                         break;
786                                 proto_tree_add_item(att_tree, stun_att_error_reason, tvb, offset+4, att_length-4, FALSE);
787
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)) {
790                                         col_append_fstr(
791                                                 pinfo->cinfo, COL_INFO,
792                                                 " %s",
793                                                 tvb_get_ephemeral_string(tvb, offset+4, att_length-4)
794                                                 );
795                                 }
796
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));
799                                 break;
800
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));
806                                 break;
807
808                         case REALM:
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)) {
812                                         col_append_fstr(
813                                                 pinfo->cinfo, COL_INFO,
814                                                 " realm: %s",
815                                                 tvb_get_ephemeral_string(tvb,offset, att_length)
816                                                 );
817                                 }
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));
820                                 break;
821
822                         case NONCE:
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)) {
826                                         col_append_fstr(
827                                                 pinfo->cinfo, COL_INFO,
828                                                 " with nonce"
829                                                 );
830                                 }
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));
833                                 break;
834
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:
840                                 if (att_length < 1)
841                                         break;
842                                         proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset, 1, 1);
843                                 if (att_length < 2)
844                                         break;
845                                 proto_tree_add_item(att_tree, stun_att_family, tvb, offset+1, 1, FALSE);
846                                 if (att_length < 4)
847                                         break;
848                                 proto_tree_add_item(att_tree, stun_att_xor_port, tvb, offset+2, 2, FALSE);
849
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);
857
858                                 if (att_length < 8)
859                                         break;
860                                 switch (tvb_get_guint8(tvb, offset+1)) {
861                                         case 1:
862                                         if (att_length < 8)
863                                                 break;
864                                         proto_tree_add_item(att_tree, stun_att_xor_ipv4, tvb, offset+4, 4, FALSE);
865
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);
873
874                                         {
875                                                 const gchar *ipstr;
876                                                 guint32 ip;
877                                                 guint16 port;
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)) {
883                                                         col_append_fstr(
884                                                                 pinfo->cinfo, COL_INFO,
885                                                                 " %s: %s:%d",
886                                                                 val_to_str(att_type, attributes, "Unknown"),
887                                                                 ipstr,
888                                                                 port
889                                                                 );
890                                                 }
891                                         }
892                                         break;
893
894                                 case 2:
895                                         if (att_length < 20)
896                                                 break;
897                                         proto_tree_add_item(att_tree, stun_att_xor_ipv6, tvb, offset+4, 16, FALSE);
898                                         {
899                                                 guint32 IPv6[4];
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); 
907                                         }
908
909                                         break;
910                                 }
911                                 break;
912                                 
913                         case REQUESTED_ADDRESS_TYPE:
914                                 if (att_length < 1)
915                                         break;
916                                 proto_tree_add_item(att_tree, stun_att_family, tvb, offset, 1, FALSE);
917                                 if (att_length < 4)
918                                         break;
919                                 proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset+1, 3, 3);
920                                 break;
921 case EVEN_PORT:
922                                 if (att_length < 1)
923                                         break;
924                                 proto_tree_add_item(att_tree, stun_att_reserve_next, tvb, offset, 1, FALSE);
925                                 break;
926
927                         case RESERVATION_TOKEN:
928                                 if (att_length < 8)
929                                         break;
930                                 proto_tree_add_item(att_tree, stun_att_token, tvb, offset, 8, FALSE);
931                                 break;
932
933                         case PRIORITY:
934                                 if (att_length < 4)
935                                         break;
936                                 proto_tree_add_item(att_tree, stun_att_priority, tvb, offset, 4, FALSE);
937                                 break;
938
939                         case PADDING:
940                                 proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset, att_length, att_length);
941                                 break;
942
943                         case ICMP:
944                                 if (att_length < 4)
945                                         break;
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);
948                                 break;
949
950                         case SOFTWARE:
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));
954                                 break;
955
956                         case CACHE_TIMEOUT:
957                                 if (att_length < 4)
958                                         break;
959                                 proto_tree_add_item(att_tree, stun_att_cache_timeout, tvb, offset, 4, FALSE);
960                                 break;
961
962                         case FINGERPRINT:
963                                 if (att_length < 4)
964                                         break;
965                                 proto_tree_add_item(att_tree, stun_att_crc32, tvb, offset, att_length, FALSE);
966                                 break;
967
968                         case ICE_CONTROLLED:
969                         case ICE_CONTROLLING:
970                                 if (att_length < 8)
971                                         break;
972                                 proto_tree_add_item(att_tree, stun_att_tie_breaker, tvb, offset, 8, FALSE);
973                                 break;
974
975                         case DATA:
976                                 if (att_length > 0) {
977                                         tvbuff_t *next_tvb;
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);
983                                         }
984                                         reported_len = att_length; 
985                                  
986                                   
987                                         next_tvb = 
988                                                 tvb_new_subset(tvb, offset, 
989                                                                reported_len, 
990                                                                reported_len);
991
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);
995                                         }
996
997                                 }
998                                 break;
999
1000                         case REQUESTED_TRANSPORT:
1001                                 if (att_length < 1)
1002                                         break;
1003                                 proto_tree_add_item(att_tree, stun_att_transp, tvb, offset, 1, FALSE);
1004                                 if (att_length < 4)
1005                                         break;
1006                                 
1007                                 {
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)) {
1011                                                 col_append_fstr(
1012                                                         pinfo->cinfo, COL_INFO,
1013                                                         " %s",
1014                                                         val_to_str(protoCode, transportnames, "Unknown (0x%8x)")
1015                                                         );
1016                                         }
1017                                 }
1018                                 proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset+1, 3, 3);
1019                                 break;
1020
1021                         case CHANNEL_NUMBER:
1022                                 if (att_length < 4)
1023                                         break;
1024                                 proto_tree_add_item(att_tree, stun_att_channelnum, tvb, offset, 2, FALSE);
1025                                 {
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)) {
1029                                                 col_append_fstr(
1030                                                         pinfo->cinfo, COL_INFO,
1031                                                         " ChannelNumber=0x%x",
1032                                                         chan
1033                                                         );
1034                                         }
1035                                 }
1036                                 proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset+2, 2, 2);
1037                                 break;
1038
1039                         case BANDWIDTH:
1040                                 if (att_length < 4)
1041                                         break;
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)) {
1045                                         col_append_fstr(
1046                                                 pinfo->cinfo, COL_INFO,
1047                                                 " bandwidth: %d",
1048                                                 tvb_get_ntohl(tvb, offset)
1049                                                 );
1050                                 }
1051                                 break;
1052                         case LIFETIME:
1053                                 if (att_length < 4)
1054                                         break;
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)) {
1058                                         col_append_fstr(
1059                                                 pinfo->cinfo, COL_INFO,
1060                                                 " lifetime: %d",
1061                                                 tvb_get_ntohl(tvb, offset)
1062                                                 );
1063                                 }
1064                                 break;
1065
1066                         default:
1067                                 if (att_length > 0)
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));
1071                                 break;
1072                         }
1073                         offset += (att_length+3) & -4;
1074                         msg_length -= (ATTR_HDR_LEN+att_length+3) & -4;
1075                 }
1076         }
1077
1078         return tvb_length(tvb);
1079 }
1080
1081 static int
1082 dissect_stun_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1083 {
1084         return dissect_stun_message(tvb, pinfo, tree);
1085 }
1086
1087 static void
1088 dissect_stun_message_no_return(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1089 {
1090         dissect_stun_message(tvb, pinfo, tree);
1091 }
1092
1093 static void
1094 dissect_stun_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1095 {
1096         tcp_dissect_pdus(tvb, pinfo, tree, TRUE, MIN_HDR_LEN,
1097                 get_stun_message_len, dissect_stun_message_no_return);
1098 }
1099
1100 static gboolean
1101 dissect_stun_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1102 {
1103         if (dissect_stun_message(tvb, pinfo, tree) == 0) {
1104                 /*
1105                  * It wasn't a valid STUN message, and wasn't
1106                  * dissected as such.
1107                  */
1108                 return FALSE;
1109         }
1110         return TRUE;
1111 }
1112
1113 void
1114 proto_register_stun(void)
1115 {
1116         static hf_register_info hf[] = {
1117
1118                 { &hf_stun_channel,
1119                   { "Channel Number",   "stun.channel", FT_UINT16,
1120                     BASE_HEX,   NULL,   0x0,    NULL,   HFILL }
1121                 },
1122
1123                 /* ////////////////////////////////////// */
1124                 { &hf_stun_type,
1125                   { "Message Type",     "stun.type",    FT_UINT16,
1126                     BASE_HEX,   NULL,   0,      NULL,   HFILL }
1127                 },
1128                 { &hf_stun_type_class,
1129                   { "Message Class",    "stun.type.class",      FT_UINT16,
1130                     BASE_HEX,   NULL,   0x0110,         NULL,   HFILL }
1131                 },
1132                 { &hf_stun_type_method,
1133                   { "Message Method",   "stun.type.method",     FT_UINT16,
1134                     BASE_HEX,   NULL,   0x3EEF,         NULL,   HFILL }
1135                 },
1136                 { &hf_stun_type_method_assignment,
1137                   { "Message Method Assignment",        "stun.type.method-assignment",  FT_UINT16,
1138                     BASE_HEX,   NULL,   0x2000,         NULL,   HFILL }
1139                 },
1140                 { &hf_stun_length,
1141                   { "Message Length",   "stun.length",  FT_UINT16,
1142                     BASE_DEC,   NULL,   0x0,    NULL,   HFILL }
1143                 },
1144                 { &hf_stun_cookie,
1145                   { "Message Cookie",   "stun.cookie",  FT_BYTES,
1146                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1147                 },
1148                 { &hf_stun_id,
1149                   { "Message Transaction ID",   "stun.id",      FT_BYTES,
1150                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1151                 },
1152                 { &hf_stun_attributes,
1153                   { "Attributes",               "stun.attributes",      FT_NONE,
1154                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1155                 },
1156                 { &hf_stun_attr,
1157                   { "Attribute Type",   "stun.attribute",       FT_UINT16,
1158                     BASE_HEX,   NULL,   0,      NULL,   HFILL }
1159                 },
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 }
1163                 },
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 }
1167                 },
1168                 { &hf_stun_time,
1169                   { "Time", "stun.time", FT_RELATIVE_TIME, 
1170                     BASE_NONE, NULL, 0x0, "The time between the Request and the Response", HFILL }
1171                 },
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 }
1175                 },
1176                 /* ////////////////////////////////////// */
1177                 { &stun_att_type,
1178                   { "Attribute Type",   "stun.att.type",        FT_UINT16,
1179                     BASE_HEX,   VALS(attributes),       0x0,    NULL,   HFILL }
1180                 },
1181                 { &stun_att_type_comprehension,
1182                   { "Attribute Type Comprehension",     "stun.att.type.comprehension",  FT_UINT16,
1183                     BASE_HEX,   NULL,   0x8000,         NULL,   HFILL }
1184                 },
1185                 { &stun_att_type_assignment,
1186                   { "Attribute Type Assignment",        "stun.att.type.assignment",     FT_UINT16,
1187                     BASE_HEX,   NULL,   0x4000,         NULL,   HFILL }
1188                 },
1189                 { &stun_att_length,
1190                   { "Attribute Length", "stun.att.length",      FT_UINT16,
1191                     BASE_DEC,   NULL,   0x0,    NULL,   HFILL }
1192                 },
1193                 { &stun_att_family,
1194                   { "Protocol Family",  "stun.att.family",      FT_UINT8,
1195                     BASE_HEX,   VALS(attributes_family),        0x0,    NULL,   HFILL }
1196                 },
1197                 { &stun_att_ipv4,
1198                   { "IP",               "stun.att.ipv4",        FT_IPv4,
1199                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1200                 },
1201                 { &stun_att_ipv6,
1202                   { "IP",               "stun.att.ipv6",        FT_IPv6,
1203                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1204                 },
1205                 { &stun_att_port,
1206                   { "Port",     "stun.att.port",        FT_UINT16,
1207                     BASE_DEC,   NULL,   0x0,    NULL,   HFILL }
1208                 },
1209                 { &stun_att_username,
1210                   { "Username", "stun.att.username",    FT_STRING,
1211                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1212                 },
1213                 { &stun_att_padding,
1214                   { "Padding",  "stun.att.padding",     FT_UINT16,
1215                     BASE_DEC,   NULL,   0x0,    NULL,   HFILL }
1216                 },
1217                 { &stun_att_hmac,
1218                   { "HMAC-SHA1",        "stun.att.hmac",        FT_BYTES,
1219                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1220                 },
1221                 { &stun_att_crc32,
1222                   { "CRC-32",   "stun.att.crc32",       FT_UINT32,
1223                     BASE_HEX,   NULL,   0x0,    NULL,   HFILL }
1224                 },
1225                 { &stun_att_error_class,
1226                   { "Error Class","stun.att.error.class",       FT_UINT8,
1227                     BASE_DEC,   NULL,   0x07,   NULL,   HFILL}
1228                 },
1229                 { &stun_att_error_number,
1230                   { "Error Code","stun.att.error",      FT_UINT8,
1231                     BASE_DEC,   NULL,   0x0,    NULL,   HFILL}
1232                 },
1233                 { &stun_att_error_reason,
1234                   { "Error Reason Phrase","stun.att.error.reason",      FT_STRING,
1235                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL}
1236                 },
1237                 { &stun_att_realm,
1238                   { "Realm",    "stun.att.realm",       FT_STRING,
1239                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1240                 },
1241                 { &stun_att_nonce,
1242                   { "Nonce",    "stun.att.nonce",       FT_STRING,
1243                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1244                 },
1245                 { &stun_att_unknown,
1246                   { "Unknown Attribute","stun.att.unknown",     FT_UINT16,
1247                     BASE_HEX,   NULL,   0x0,    NULL,   HFILL}
1248                 },
1249                 { &stun_att_xor_ipv4,
1250                   { "IP (XOR-d)",               "stun.att.ipv4-xord",   FT_BYTES,
1251                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1252                 },
1253                 { &stun_att_xor_ipv6,
1254                   { "IP (XOR-d)",               "stun.att.ipv6-xord",   FT_BYTES,
1255                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1256                 },
1257                 { &stun_att_xor_port,
1258                   { "Port (XOR-d)",     "stun.att.port-xord",   FT_BYTES,
1259                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1260                 },
1261                 { &stun_att_icmp_type,
1262                   { "ICMP type",                "stun.att.icmp.type",   FT_UINT8,
1263                     BASE_DEC,   NULL,   0x0,    NULL,   HFILL}
1264                 },
1265                 { &stun_att_icmp_code,
1266                   { "ICMP code",                "stun.att.icmp.code",   FT_UINT8,
1267                     BASE_DEC,   NULL,   0x0,    NULL,   HFILL}
1268                 },
1269                 { &stun_att_software,
1270                   { "Software","stun.att.software",     FT_STRING,
1271                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL}
1272                 },
1273                 { &stun_att_priority,
1274                   { "Priority",         "stun.att.priority",    FT_UINT32,
1275                     BASE_DEC,   NULL,   0x0,    NULL,   HFILL}
1276                 },
1277                 { &stun_att_tie_breaker,
1278                   { "Tie breaker",      "stun.att.tie-breaker", FT_BYTES,
1279                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1280                 },
1281                 { &stun_att_lifetime,
1282                   { "Lifetime",         "stun.att.lifetime",    FT_UINT32,
1283                     BASE_DEC,   NULL,   0x0,    NULL,   HFILL}
1284                 },
1285                 { &stun_att_change_ip,
1286                   { "Change IP","stun.att.change-ip",   FT_BOOLEAN,
1287                     16,         TFS(&tfs_set_notset),   0x0004, NULL,   HFILL}
1288                 },
1289                 { &stun_att_change_port,
1290                   { "Change Port","stun.att.change-port",       FT_BOOLEAN,
1291                     16,         TFS(&tfs_set_notset),   0x0002, NULL,   HFILL}
1292                 },              
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}
1296                 },              
1297                 { &stun_att_cache_timeout,
1298                   { "Cache timeout",            "stun.att.cache-timeout",       FT_UINT32,
1299                     BASE_DEC,   NULL,   0x0,    NULL,   HFILL}
1300                 },
1301                 { &stun_att_token,
1302                   { "Token",    "stun.att.token",       FT_BYTES,
1303                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1304                 },
1305                 { &stun_att_value,
1306                   { "Value",    "stun.value",   FT_BYTES,
1307                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1308                 },
1309                 { &stun_att_reserved,
1310                   { "Reserved", "stun.att.reserved",    FT_UINT16,
1311                     BASE_DEC,   NULL,   0x0,    NULL,   HFILL }
1312                 },
1313                 { &stun_att_transp,
1314                   { "Transport",        "stun.att.transp",      FT_UINT8,
1315                     BASE_HEX,   VALS(transportnames),   0x0,    NULL,   HFILL }
1316                 },
1317                 { &stun_att_channelnum,
1318                   { "Channel-Number",   "stun.att.channelnum",  FT_UINT16,
1319                     BASE_HEX,   NULL,   0x0,    NULL,   HFILL }
1320                 },
1321                 { &stun_att_bandwidth,
1322                   { "Bandwidth",        "stun.port.bandwidth",  FT_UINT32,
1323                     BASE_DEC,   NULL,   0x0,    NULL, HFILL }
1324                 },
1325         };
1326
1327         /* Setup protocol subtree array */
1328         static gint *ett[] = {
1329                 &ett_stun,
1330                 &ett_stun_type,
1331                 &ett_stun_att_all,
1332                 &ett_stun_att,
1333                 &ett_stun_att_type,
1334         };
1335
1336         /* Register the protocol name and description */
1337         proto_stun = proto_register_protocol("Session Traversal Utilities for NAT", "STUN", "stun");
1338
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));
1342
1343         /* heuristic subdissectors (used for the DATA field) */
1344         register_heur_dissector_list("stun", &heur_subdissector_list);
1345 }
1346
1347 void
1348 proto_reg_handoff_stun(void)
1349 {
1350         dissector_handle_t stun_tcp_handle;
1351         dissector_handle_t stun_udp_handle;
1352
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);
1355
1356         dissector_add("tcp.port", TCP_PORT_STUN, stun_tcp_handle);
1357         dissector_add("udp.port", UDP_PORT_STUN, stun_udp_handle);
1358
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);
1362
1363         data_handle = find_dissector("data");
1364 }
1365