From Didier Gautheron:
[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         ti = proto_tree_add_item(tree, proto_stun, tvb, 0, -1, FALSE);
570
571         stun_tree = proto_item_add_subtree(ti, ett_stun);
572
573
574         if (msg_type_class == REQUEST) {
575                 if (stun_trans->req_frame != pinfo->fd->num) {
576                         proto_item *it;
577                         it=proto_tree_add_uint(stun_tree, hf_stun_duplicate, 
578                                                tvb, 0, 0, 
579                                                stun_trans->req_frame);
580                         PROTO_ITEM_SET_GENERATED(it);
581                 }
582                 if (stun_trans->rep_frame) {
583                         proto_item *it;
584                         it=proto_tree_add_uint(stun_tree, hf_stun_response_in, 
585                                                tvb, 0, 0, 
586                                                stun_trans->rep_frame);
587                         PROTO_ITEM_SET_GENERATED(it);
588                 }
589         }
590         else {
591                 /* Retransmission control */
592                 if (stun_trans->rep_frame != pinfo->fd->num) {
593                         proto_item *it;
594                         it=proto_tree_add_uint(stun_tree, hf_stun_duplicate, 
595                                                tvb, 0, 0, 
596                                                stun_trans->rep_frame);
597                         PROTO_ITEM_SET_GENERATED(it);
598                 }
599                 if (msg_type_class == RESPONSE || msg_type_class == ERROR_RESPONSE) {
600                         /* This is a response */
601                         if (stun_trans->req_frame) {
602                                 proto_item *it;
603                                 nstime_t ns;
604
605                                 it=proto_tree_add_uint(stun_tree, hf_stun_response_to, tvb, 0, 0,
606                                                        stun_trans->req_frame);
607                                 PROTO_ITEM_SET_GENERATED(it);
608
609                                 nstime_delta(&ns, &pinfo->fd->abs_ts, &stun_trans->req_time);
610                                 it=proto_tree_add_time(stun_tree, hf_stun_time, tvb, 0, 0, &ns);
611                                 PROTO_ITEM_SET_GENERATED(it);
612                         }
613     
614                 }
615         }
616
617         ti = proto_tree_add_uint_format(stun_tree, hf_stun_type, tvb, 0, 2,
618                                         msg_type, "Message Type: 0x%04x (%s %s)", msg_type, msg_method_str, msg_class_str);
619         stun_type_tree = proto_item_add_subtree(ti, ett_stun_type);
620         proto_tree_add_uint(stun_type_tree, hf_stun_type_class, tvb, 0, 2, msg_type);
621         ti = proto_tree_add_text(stun_type_tree, tvb, 0, 2, "%s (%d)", msg_class_str, msg_type_class);
622         PROTO_ITEM_SET_GENERATED(ti);
623         proto_tree_add_uint(stun_type_tree, hf_stun_type_method, tvb, 0, 2, msg_type);
624         ti = proto_tree_add_text(stun_type_tree, tvb, 0, 2, "%s (0x%03x)", msg_method_str, msg_type_method);
625         PROTO_ITEM_SET_GENERATED(ti);
626         proto_tree_add_uint(stun_type_tree, hf_stun_type_method_assignment, tvb, 0, 2, msg_type);
627         ti = proto_tree_add_text(stun_type_tree, tvb, 0, 2, "%s (%d)", match_strval((msg_type & 0x2000) >> 13, assignments), (msg_type & 0x2000) >> 13);
628         PROTO_ITEM_SET_GENERATED(ti);
629
630         proto_tree_add_uint(stun_tree, hf_stun_length, tvb, 2, 2, msg_length);
631         proto_tree_add_item(stun_tree, hf_stun_cookie, tvb, 4, 4, FALSE);
632         proto_tree_add_item(stun_tree, hf_stun_id, tvb, 8, 12, FALSE);
633
634         /* Remember this (in host order) so we can show clear xor'd addresses */
635         magic_cookie_first_word = tvb_get_ntohl(tvb, 4);
636
637         if (msg_length > 0) {
638                 ti = proto_tree_add_item(stun_tree, hf_stun_attributes, tvb, STUN_HDR_LEN, msg_length, FALSE);
639                 att_all_tree = proto_item_add_subtree(ti, ett_stun_att_all);
640
641                 offset = STUN_HDR_LEN;
642
643                 while (msg_length > 0) {
644                         att_type = tvb_get_ntohs(tvb, offset); /* Type field in attribute header */
645                         att_length = tvb_get_ntohs(tvb, offset+2); /* Length field in attribute header */
646                         att_type_str = match_strval(att_type, attributes);
647                         if (att_type_str == NULL)
648                                 att_type_str = "Unknown";
649                         ti = proto_tree_add_uint_format(att_all_tree, hf_stun_attr, 
650                                                         tvb, offset, ATTR_HDR_LEN+att_length,
651                                                         att_type, "%s", att_type_str);
652                         att_tree = proto_item_add_subtree(ti, ett_stun_att);
653                         ti = proto_tree_add_uint(att_tree, stun_att_type, tvb,
654                                                  offset, 2, att_type);
655                         att_type_tree = proto_item_add_subtree(ti, ett_stun_att_type);
656                         proto_tree_add_uint(att_type_tree, stun_att_type_comprehension, tvb, offset, 2, att_type);
657                         ti = proto_tree_add_text(att_type_tree, tvb, offset, 2,
658                                                  "%s (%d)",
659                                                  match_strval((att_type & 0x8000) >> 15, comprehensions),
660                                                  (att_type & 0x8000) >> 15);
661                         PROTO_ITEM_SET_GENERATED(ti);
662                         proto_tree_add_uint(att_type_tree, stun_att_type_assignment, tvb, offset, 2, att_type);
663                         ti = proto_tree_add_text(att_type_tree, tvb, offset, 2,
664                                                  "%s (%d)",
665                                                  match_strval((att_type & 0x4000) >> 14, assignments),
666                                                  (att_type & 0x4000) >> 14);
667                         PROTO_ITEM_SET_GENERATED(ti);
668
669                         offset += 2;
670                         if (ATTR_HDR_LEN+att_length > msg_length) {
671                                 proto_tree_add_uint_format(att_tree,
672                                                            stun_att_length, tvb, offset, 2,
673                                                            att_length,
674                                                            "Attribute Length: %u (bogus, goes past the end of the message)",
675                                                            att_length);
676                                 break;
677                         }
678                         proto_tree_add_uint(att_tree, stun_att_length, tvb,
679                                             offset, 2, att_length);
680                         offset += 2;
681                         switch (att_type) {
682                         case MAPPED_ADDRESS:
683                         case ALTERNATE_SERVER:
684                         case RESPONSE_ORIGIN:
685                         case OTHER_ADDRESS:
686                                 if (att_length < 1)
687                                         break;
688                                 proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset, 1, 1);
689                                 if (att_length < 2)
690                                         break;
691                                 proto_tree_add_item(att_tree, stun_att_family, tvb, offset+1, 1, FALSE);
692                                 if (att_length < 4)
693                                         break;
694                                 proto_tree_add_item(att_tree, stun_att_port, tvb, offset+2, 2, FALSE);
695                                 switch (tvb_get_guint8(tvb, offset+1)) {
696                                 case 1:
697                                         if (att_length < 8)
698                                                 break;
699                                         proto_tree_add_item(att_tree, stun_att_ipv4, tvb, offset+4, 4, FALSE);
700                                         {
701                                                 const gchar *ipstr;
702                                                 guint32 ip;
703                                                 ip = tvb_get_ipv4(tvb,offset+4);
704                                                 ipstr = ip_to_str((guint8*)&ip);
705                                                 proto_item_append_text(att_tree, ": %s:%d", ipstr,tvb_get_ntohs(tvb,offset+2));
706                                                 if(check_col(pinfo->cinfo,COL_INFO)) {
707                                                         col_append_fstr(
708                                                                 pinfo->cinfo, COL_INFO,
709                                                                 " %s: %s:%d",
710                                                                 val_to_str(att_type, attributes, "Unknown"),
711                                                                 ipstr,
712                                                                 tvb_get_ntohs(tvb,offset+2)
713                                                                 );
714                                                 }
715                                         }
716                                         break;
717
718                                 case 2:
719                                         if (att_length < 20)
720                                                 break;
721                                         proto_tree_add_item(att_tree, stun_att_ipv6, tvb, offset+4, 16, FALSE);
722                                         break;
723                                 }
724                                 break;
725
726                         case CHANGE_REQUEST:
727                                 if (att_length < 4)
728                                         break;
729                                 proto_tree_add_item(att_tree, stun_att_change_ip, tvb, offset, 4, FALSE);
730                                 proto_tree_add_item(att_tree, stun_att_change_port, tvb, offset, 4, FALSE);
731                                 break;
732
733                         case USERNAME:
734                                 proto_tree_add_item(att_tree, stun_att_username, tvb, offset, att_length, FALSE);
735                                 proto_item_append_text(att_tree, ": %s", tvb_get_ephemeral_string(tvb, offset, att_length));
736                                 if(check_col(pinfo->cinfo,COL_INFO)) {
737                                         col_append_fstr(
738                                                 pinfo->cinfo, COL_INFO,
739                                                 " user: %s",
740                                                 tvb_get_ephemeral_string(tvb,offset, att_length)
741                                                 );
742                                 }
743                                 if (att_length % 4 != 0)
744                                         proto_tree_add_uint(att_tree, stun_att_padding, 
745                                                             tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
746                                 break;
747
748                         case MESSAGE_INTEGRITY:
749                                 if (att_length < 20)
750                                         break;
751                                 proto_tree_add_item(att_tree, stun_att_hmac, tvb, offset, att_length, FALSE);
752                                 break;
753
754                         case ERROR_CODE:
755                                 if (att_length < 2)
756                                         break;
757                                 proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset, 2, 2);
758                                 if (att_length < 3)
759                                         break;
760                                 proto_tree_add_item(att_tree, stun_att_error_class, tvb, offset+2, 1, FALSE);
761                                 if (att_length < 4)
762                                         break;
763                                 proto_tree_add_item(att_tree, stun_att_error_number, tvb, offset+3, 1, FALSE);
764                                 {
765                                         int human_error_num = tvb_get_guint8(tvb, offset+2) * 100 + tvb_get_guint8(tvb, offset+3);
766                                         proto_item_append_text(
767                                                 att_tree,
768                                                 " %d (%s)",
769                                                 human_error_num, /* human readable error code */
770                                                 val_to_str(human_error_num, error_code, "*Unknown error code*")
771                                                 );
772                                         if(check_col(pinfo->cinfo,COL_INFO)) {
773                                                 col_append_fstr(
774                                                         pinfo->cinfo, COL_INFO,
775                                                         " error-code: %d (%s)",
776                                                         human_error_num,
777                                                         val_to_str(human_error_num, error_code, "*Unknown error code*")
778                                                         );
779                                         }
780                                 }
781                                 if (att_length < 5)
782                                         break;
783                                 proto_tree_add_item(att_tree, stun_att_error_reason, tvb, offset+4, att_length-4, FALSE);
784
785                                 proto_item_append_text(att_tree, ": %s", tvb_get_ephemeral_string(tvb, offset+4, att_length-4));
786                                 if(check_col(pinfo->cinfo,COL_INFO)) {
787                                         col_append_fstr(
788                                                 pinfo->cinfo, COL_INFO,
789                                                 " %s",
790                                                 tvb_get_ephemeral_string(tvb, offset+4, att_length-4)
791                                                 );
792                                 }
793
794                                 if (att_length % 4 != 0)
795                                         proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
796                                 break;
797
798                         case UNKNOWN_ATTRIBUTES:
799                                 for (i = 0; i < att_length; i += 2)
800                                         proto_tree_add_item(att_tree, stun_att_unknown, tvb, offset+i, 2, FALSE);
801                                 if (att_length % 4 != 0)
802                                         proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
803                                 break;
804
805                         case REALM:
806                                 proto_tree_add_item(att_tree, stun_att_realm, tvb, offset, att_length, FALSE);
807                                 proto_item_append_text(att_tree, ": %s", tvb_get_ephemeral_string(tvb, offset, att_length));
808                                 if(check_col(pinfo->cinfo,COL_INFO)) {
809                                         col_append_fstr(
810                                                 pinfo->cinfo, COL_INFO,
811                                                 " realm: %s",
812                                                 tvb_get_ephemeral_string(tvb,offset, att_length)
813                                                 );
814                                 }
815                                 if (att_length % 4 != 0)
816                                         proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
817                                 break;
818
819                         case NONCE:
820                                 proto_tree_add_item(att_tree, stun_att_nonce, tvb, offset, att_length, FALSE);
821                                 proto_item_append_text(att_tree, ": %s", tvb_get_ephemeral_string(tvb, offset, att_length));
822                                 if(check_col(pinfo->cinfo,COL_INFO)) {
823                                         col_append_fstr(
824                                                 pinfo->cinfo, COL_INFO,
825                                                 " with nonce"
826                                                 );
827                                 }
828                                 if (att_length % 4 != 0)
829                                         proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
830                                 break;
831
832                         case XOR_MAPPED_ADDRESS:
833                         case XOR_PEER_ADDRESS:
834                         case XOR_RELAYED_ADDRESS:
835                         case XOR_RESPONSE_TARGET:
836                         case XOR_REFLECTED_FROM:
837                                 if (att_length < 1)
838                                         break;
839                                         proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset, 1, 1);
840                                 if (att_length < 2)
841                                         break;
842                                 proto_tree_add_item(att_tree, stun_att_family, tvb, offset+1, 1, FALSE);
843                                 if (att_length < 4)
844                                         break;
845                                 proto_tree_add_item(att_tree, stun_att_xor_port, tvb, offset+2, 2, FALSE);
846
847                                 /* Show the port 'in the clear'
848                                 XOR (host order) transid with (host order) xor-port.
849                                 Add host-order port into tree. */
850                                 ti = proto_tree_add_uint(att_tree, stun_att_port, tvb, offset+2, 2,
851                                         tvb_get_ntohs(tvb, offset+2) ^
852                                         (magic_cookie_first_word >> 16));
853                                 PROTO_ITEM_SET_GENERATED(ti);
854
855                                 if (att_length < 8)
856                                         break;
857                                 switch (tvb_get_guint8(tvb, offset+1)) {
858                                         case 1:
859                                         if (att_length < 8)
860                                                 break;
861                                         proto_tree_add_item(att_tree, stun_att_xor_ipv4, tvb, offset+4, 4, FALSE);
862
863                                         /* Show the address 'in the clear'.
864                                         XOR (host order) transid with (host order) xor-address.
865                                         Add in network order tree. */
866                                         ti = proto_tree_add_ipv4(att_tree, stun_att_ipv4, tvb, offset+4, 4,
867                                                 g_htonl(tvb_get_ntohl(tvb, offset+4) ^
868                                                 magic_cookie_first_word));
869                                         PROTO_ITEM_SET_GENERATED(ti);
870
871                                         {
872                                                 const gchar *ipstr;
873                                                 guint32 ip;
874                                                 guint16 port;
875                                                 ip = g_htonl(tvb_get_ntohl(tvb, offset+4) ^ magic_cookie_first_word);
876                                                 ipstr = ip_to_str((guint8*)&ip);
877                                                 port = tvb_get_ntohs(tvb, offset+2) ^ (magic_cookie_first_word >> 16);
878                                                 proto_item_append_text(att_tree, ": %s:%d", ipstr, port);
879                                                 if(check_col(pinfo->cinfo,COL_INFO)) {
880                                                         col_append_fstr(
881                                                                 pinfo->cinfo, COL_INFO,
882                                                                 " %s: %s:%d",
883                                                                 val_to_str(att_type, attributes, "Unknown"),
884                                                                 ipstr,
885                                                                 port
886                                                                 );
887                                                 }
888                                         }
889                                         break;
890
891                                 case 2:
892                                         if (att_length < 20)
893                                                 break;
894                                         proto_tree_add_item(att_tree, stun_att_xor_ipv6, tvb, offset+4, 16, FALSE);
895                                         {
896                                                 guint32 IPv6[4];
897                                                 IPv6[0] = g_htonl(tvb_get_ntohl(tvb, offset+4) ^ magic_cookie_first_word);
898                                                 IPv6[1] = g_htonl(tvb_get_ntohl(tvb, offset+8) ^ transaction_id[0]);
899                                                 IPv6[2] = g_htonl(tvb_get_ntohl(tvb, offset+12) ^ transaction_id[1]);
900                                                 IPv6[3] = g_htonl(tvb_get_ntohl(tvb, offset+16) ^ transaction_id[2]);
901                                                 ti = proto_tree_add_ipv6(att_tree, stun_att_ipv6, tvb, offset+4, 16,
902                                                                          (const guint8 *)IPv6);
903                                                 PROTO_ITEM_SET_GENERATED(ti); 
904                                         }
905
906                                         break;
907                                 }
908                                 break;
909                                 
910                         case REQUESTED_ADDRESS_TYPE:
911                                 if (att_length < 1)
912                                         break;
913                                 proto_tree_add_item(att_tree, stun_att_family, tvb, offset, 1, FALSE);
914                                 if (att_length < 4)
915                                         break;
916                                 proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset+1, 3, 3);
917                                 break;
918 case EVEN_PORT:
919                                 if (att_length < 1)
920                                         break;
921                                 proto_tree_add_item(att_tree, stun_att_reserve_next, tvb, offset, 1, FALSE);
922                                 break;
923
924                         case RESERVATION_TOKEN:
925                                 if (att_length < 8)
926                                         break;
927                                 proto_tree_add_item(att_tree, stun_att_token, tvb, offset, 8, FALSE);
928                                 break;
929
930                         case PRIORITY:
931                                 if (att_length < 4)
932                                         break;
933                                 proto_tree_add_item(att_tree, stun_att_priority, tvb, offset, 4, FALSE);
934                                 break;
935
936                         case PADDING:
937                                 proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset, att_length, att_length);
938                                 break;
939
940                         case ICMP:
941                                 if (att_length < 4)
942                                         break;
943                                 proto_tree_add_item(att_tree, stun_att_icmp_type, tvb, offset, 1, FALSE);
944                                 proto_tree_add_item(att_tree, stun_att_icmp_code, tvb, offset+1, 1, FALSE);
945                                 break;
946
947                         case SOFTWARE:
948                                 proto_tree_add_item(att_tree, stun_att_software, tvb, offset, att_length, FALSE);
949                                 if (att_length % 4 != 0)
950                                         proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
951                                 break;
952
953                         case CACHE_TIMEOUT:
954                                 if (att_length < 4)
955                                         break;
956                                 proto_tree_add_item(att_tree, stun_att_cache_timeout, tvb, offset, 4, FALSE);
957                                 break;
958
959                         case FINGERPRINT:
960                                 if (att_length < 4)
961                                         break;
962                                 proto_tree_add_item(att_tree, stun_att_crc32, tvb, offset, att_length, FALSE);
963                                 break;
964
965                         case ICE_CONTROLLED:
966                         case ICE_CONTROLLING:
967                                 if (att_length < 8)
968                                         break;
969                                 proto_tree_add_item(att_tree, stun_att_tie_breaker, tvb, offset, 8, FALSE);
970                                 break;
971
972                         case DATA:
973                                 if (att_length > 0) {
974                                         tvbuff_t *next_tvb;
975                                         guint reported_len, pad=0;
976                                         proto_tree_add_item(att_tree, stun_att_value, tvb, offset, att_length, FALSE);
977                                         if (att_length % 4 != 0) {
978                                                 pad = 4-(att_length % 4);
979                                                 proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, pad, pad);
980                                         }
981                                         reported_len = att_length; 
982                                  
983                                   
984                                         next_tvb = 
985                                                 tvb_new_subset(tvb, offset, 
986                                                                reported_len, 
987                                                                reported_len);
988
989                                         if (!dissector_try_heuristic(heur_subdissector_list, 
990                                                                      next_tvb, pinfo, att_tree)) {
991                                                 call_dissector_only(data_handle,next_tvb, pinfo, att_tree);
992                                         }
993
994                                 }
995                                 break;
996
997                         case REQUESTED_TRANSPORT:
998                                 if (att_length < 1)
999                                         break;
1000                                 proto_tree_add_item(att_tree, stun_att_transp, tvb, offset, 1, FALSE);
1001                                 if (att_length < 4)
1002                                         break;
1003                                 
1004                                 {
1005                                         guint8  protoCode = tvb_get_guint8(tvb, offset);
1006                                         proto_item_append_text(att_tree, ": %s", val_to_str(protoCode, transportnames, "Unknown (0x%8x)"));
1007                                         if(check_col(pinfo->cinfo,COL_INFO)) {
1008                                                 col_append_fstr(
1009                                                         pinfo->cinfo, COL_INFO,
1010                                                         " %s",
1011                                                         val_to_str(protoCode, transportnames, "Unknown (0x%8x)")
1012                                                         );
1013                                         }
1014                                 }
1015                                 proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset+1, 3, 3);
1016                                 break;
1017
1018                         case CHANNEL_NUMBER:
1019                                 if (att_length < 4)
1020                                         break;
1021                                 proto_tree_add_item(att_tree, stun_att_channelnum, tvb, offset, 2, FALSE);
1022                                 {
1023                                         guint16 chan = tvb_get_ntohs(tvb, offset);
1024                                         proto_item_append_text(att_tree, ": 0x%x", chan);
1025                                         if(check_col(pinfo->cinfo,COL_INFO)) {
1026                                                 col_append_fstr(
1027                                                         pinfo->cinfo, COL_INFO,
1028                                                         " ChannelNumber=0x%x",
1029                                                         chan
1030                                                         );
1031                                         }
1032                                 }
1033                                 proto_tree_add_uint(att_tree, stun_att_reserved, tvb, offset+2, 2, 2);
1034                                 break;
1035
1036                         case BANDWIDTH:
1037                                 if (att_length < 4)
1038                                         break;
1039                                 proto_tree_add_item(att_tree, stun_att_bandwidth, tvb, offset, 4, FALSE);
1040                                 proto_item_append_text(att_tree, " %d", tvb_get_ntohl(tvb, offset));
1041                                 if(check_col(pinfo->cinfo,COL_INFO)) {
1042                                         col_append_fstr(
1043                                                 pinfo->cinfo, COL_INFO,
1044                                                 " bandwidth: %d",
1045                                                 tvb_get_ntohl(tvb, offset)
1046                                                 );
1047                                 }
1048                                 break;
1049                         case LIFETIME:
1050                                 if (att_length < 4)
1051                                         break;
1052                                 proto_tree_add_item(att_tree, stun_att_lifetime, tvb, offset, 4, FALSE);
1053                                 proto_item_append_text(att_tree, " %d", tvb_get_ntohl(tvb, offset));
1054                                 if(check_col(pinfo->cinfo,COL_INFO)) {
1055                                         col_append_fstr(
1056                                                 pinfo->cinfo, COL_INFO,
1057                                                 " lifetime: %d",
1058                                                 tvb_get_ntohl(tvb, offset)
1059                                                 );
1060                                 }
1061                                 break;
1062
1063                         default:
1064                                 if (att_length > 0)
1065                                         proto_tree_add_item(att_tree, stun_att_value, tvb, offset, att_length, FALSE);
1066                                 if (att_length % 4 != 0)
1067                                         proto_tree_add_uint(att_tree, stun_att_padding, tvb, offset+att_length, 4-(att_length % 4), 4-(att_length % 4));
1068                                 break;
1069                         }
1070                         offset += (att_length+3) & -4;
1071                         msg_length -= (ATTR_HDR_LEN+att_length+3) & -4;
1072                 }
1073         }
1074
1075         return tvb_length(tvb);
1076 }
1077
1078 static int
1079 dissect_stun_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1080 {
1081         return dissect_stun_message(tvb, pinfo, tree);
1082 }
1083
1084 static void
1085 dissect_stun_message_no_return(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1086 {
1087         dissect_stun_message(tvb, pinfo, tree);
1088 }
1089
1090 static void
1091 dissect_stun_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1092 {
1093         tcp_dissect_pdus(tvb, pinfo, tree, TRUE, MIN_HDR_LEN,
1094                 get_stun_message_len, dissect_stun_message_no_return);
1095 }
1096
1097 static gboolean
1098 dissect_stun_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1099 {
1100         if (dissect_stun_message(tvb, pinfo, tree) == 0) {
1101                 /*
1102                  * It wasn't a valid STUN message, and wasn't
1103                  * dissected as such.
1104                  */
1105                 return FALSE;
1106         }
1107         return TRUE;
1108 }
1109
1110 void
1111 proto_register_stun(void)
1112 {
1113         static hf_register_info hf[] = {
1114
1115                 { &hf_stun_channel,
1116                   { "Channel Number",   "stun.channel", FT_UINT16,
1117                     BASE_HEX,   NULL,   0x0,    NULL,   HFILL }
1118                 },
1119
1120                 /* ////////////////////////////////////// */
1121                 { &hf_stun_type,
1122                   { "Message Type",     "stun.type",    FT_UINT16,
1123                     BASE_HEX,   NULL,   0,      NULL,   HFILL }
1124                 },
1125                 { &hf_stun_type_class,
1126                   { "Message Class",    "stun.type.class",      FT_UINT16,
1127                     BASE_HEX,   NULL,   0x0110,         NULL,   HFILL }
1128                 },
1129                 { &hf_stun_type_method,
1130                   { "Message Method",   "stun.type.method",     FT_UINT16,
1131                     BASE_HEX,   NULL,   0x3EEF,         NULL,   HFILL }
1132                 },
1133                 { &hf_stun_type_method_assignment,
1134                   { "Message Method Assignment",        "stun.type.method-assignment",  FT_UINT16,
1135                     BASE_HEX,   NULL,   0x2000,         NULL,   HFILL }
1136                 },
1137                 { &hf_stun_length,
1138                   { "Message Length",   "stun.length",  FT_UINT16,
1139                     BASE_DEC,   NULL,   0x0,    NULL,   HFILL }
1140                 },
1141                 { &hf_stun_cookie,
1142                   { "Message Cookie",   "stun.cookie",  FT_BYTES,
1143                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1144                 },
1145                 { &hf_stun_id,
1146                   { "Message Transaction ID",   "stun.id",      FT_BYTES,
1147                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1148                 },
1149                 { &hf_stun_attributes,
1150                   { "Attributes",               "stun.attributes",      FT_NONE,
1151                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1152                 },
1153                 { &hf_stun_attr,
1154                   { "Attribute Type",   "stun.attribute",       FT_UINT16,
1155                     BASE_HEX,   NULL,   0,      NULL,   HFILL }
1156                 },
1157                 { &hf_stun_response_in,
1158                   { "Response In",      "stun.response-in", FT_FRAMENUM, 
1159                     BASE_NONE, NULL, 0x0, "The response to this STUN query is in this frame", HFILL }
1160                 },
1161                 { &hf_stun_response_to,
1162                   { "Request In", "stun.response-to", FT_FRAMENUM, 
1163                     BASE_NONE, NULL, 0x0, "This is a response to the STUN Request in this frame", HFILL }
1164                 },
1165                 { &hf_stun_time,
1166                   { "Time", "stun.time", FT_RELATIVE_TIME, 
1167                     BASE_NONE, NULL, 0x0, "The time between the Request and the Response", HFILL }
1168                 },
1169                 { &hf_stun_duplicate,
1170                   { "Duplicated original message in", "stun.reqduplicate", FT_FRAMENUM, 
1171                     BASE_NONE, NULL, 0x0, "This is a duplicate of STUN message in this frame", HFILL }
1172                 },
1173                 /* ////////////////////////////////////// */
1174                 { &stun_att_type,
1175                   { "Attribute Type",   "stun.att.type",        FT_UINT16,
1176                     BASE_HEX,   VALS(attributes),       0x0,    NULL,   HFILL }
1177                 },
1178                 { &stun_att_type_comprehension,
1179                   { "Attribute Type Comprehension",     "stun.att.type.comprehension",  FT_UINT16,
1180                     BASE_HEX,   NULL,   0x8000,         NULL,   HFILL }
1181                 },
1182                 { &stun_att_type_assignment,
1183                   { "Attribute Type Assignment",        "stun.att.type.assignment",     FT_UINT16,
1184                     BASE_HEX,   NULL,   0x4000,         NULL,   HFILL }
1185                 },
1186                 { &stun_att_length,
1187                   { "Attribute Length", "stun.att.length",      FT_UINT16,
1188                     BASE_DEC,   NULL,   0x0,    NULL,   HFILL }
1189                 },
1190                 { &stun_att_family,
1191                   { "Protocol Family",  "stun.att.family",      FT_UINT8,
1192                     BASE_HEX,   VALS(attributes_family),        0x0,    NULL,   HFILL }
1193                 },
1194                 { &stun_att_ipv4,
1195                   { "IP",               "stun.att.ipv4",        FT_IPv4,
1196                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1197                 },
1198                 { &stun_att_ipv6,
1199                   { "IP",               "stun.att.ipv6",        FT_IPv6,
1200                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1201                 },
1202                 { &stun_att_port,
1203                   { "Port",     "stun.att.port",        FT_UINT16,
1204                     BASE_DEC,   NULL,   0x0,    NULL,   HFILL }
1205                 },
1206                 { &stun_att_username,
1207                   { "Username", "stun.att.username",    FT_STRING,
1208                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1209                 },
1210                 { &stun_att_padding,
1211                   { "Padding",  "stun.att.padding",     FT_UINT16,
1212                     BASE_DEC,   NULL,   0x0,    NULL,   HFILL }
1213                 },
1214                 { &stun_att_hmac,
1215                   { "HMAC-SHA1",        "stun.att.hmac",        FT_BYTES,
1216                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1217                 },
1218                 { &stun_att_crc32,
1219                   { "CRC-32",   "stun.att.crc32",       FT_UINT32,
1220                     BASE_HEX,   NULL,   0x0,    NULL,   HFILL }
1221                 },
1222                 { &stun_att_error_class,
1223                   { "Error Class","stun.att.error.class",       FT_UINT8,
1224                     BASE_DEC,   NULL,   0x07,   NULL,   HFILL}
1225                 },
1226                 { &stun_att_error_number,
1227                   { "Error Code","stun.att.error",      FT_UINT8,
1228                     BASE_DEC,   NULL,   0x0,    NULL,   HFILL}
1229                 },
1230                 { &stun_att_error_reason,
1231                   { "Error Reason Phrase","stun.att.error.reason",      FT_STRING,
1232                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL}
1233                 },
1234                 { &stun_att_realm,
1235                   { "Realm",    "stun.att.realm",       FT_STRING,
1236                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1237                 },
1238                 { &stun_att_nonce,
1239                   { "Nonce",    "stun.att.nonce",       FT_STRING,
1240                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1241                 },
1242                 { &stun_att_unknown,
1243                   { "Unknown Attribute","stun.att.unknown",     FT_UINT16,
1244                     BASE_HEX,   NULL,   0x0,    NULL,   HFILL}
1245                 },
1246                 { &stun_att_xor_ipv4,
1247                   { "IP (XOR-d)",               "stun.att.ipv4-xord",   FT_BYTES,
1248                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1249                 },
1250                 { &stun_att_xor_ipv6,
1251                   { "IP (XOR-d)",               "stun.att.ipv6-xord",   FT_BYTES,
1252                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1253                 },
1254                 { &stun_att_xor_port,
1255                   { "Port (XOR-d)",     "stun.att.port-xord",   FT_BYTES,
1256                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1257                 },
1258                 { &stun_att_icmp_type,
1259                   { "ICMP type",                "stun.att.icmp.type",   FT_UINT8,
1260                     BASE_DEC,   NULL,   0x0,    NULL,   HFILL}
1261                 },
1262                 { &stun_att_icmp_code,
1263                   { "ICMP code",                "stun.att.icmp.code",   FT_UINT8,
1264                     BASE_DEC,   NULL,   0x0,    NULL,   HFILL}
1265                 },
1266                 { &stun_att_software,
1267                   { "Software","stun.att.software",     FT_STRING,
1268                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL}
1269                 },
1270                 { &stun_att_priority,
1271                   { "Priority",         "stun.att.priority",    FT_UINT32,
1272                     BASE_DEC,   NULL,   0x0,    NULL,   HFILL}
1273                 },
1274                 { &stun_att_tie_breaker,
1275                   { "Tie breaker",      "stun.att.tie-breaker", FT_BYTES,
1276                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1277                 },
1278                 { &stun_att_lifetime,
1279                   { "Lifetime",         "stun.att.lifetime",    FT_UINT32,
1280                     BASE_DEC,   NULL,   0x0,    NULL,   HFILL}
1281                 },
1282                 { &stun_att_change_ip,
1283                   { "Change IP","stun.att.change-ip",   FT_BOOLEAN,
1284                     16,         TFS(&tfs_set_notset),   0x0004, NULL,   HFILL}
1285                 },
1286                 { &stun_att_change_port,
1287                   { "Change Port","stun.att.change-port",       FT_BOOLEAN,
1288                     16,         TFS(&tfs_set_notset),   0x0002, NULL,   HFILL}
1289                 },              
1290                 { &stun_att_reserve_next,
1291                   { "Reserve next","stun.att.even-port.reserve-next",   FT_UINT8,
1292                     BASE_DEC,   VALS(attributes_reserve_next),  0x80,   NULL,   HFILL}
1293                 },              
1294                 { &stun_att_cache_timeout,
1295                   { "Cache timeout",            "stun.att.cache-timeout",       FT_UINT32,
1296                     BASE_DEC,   NULL,   0x0,    NULL,   HFILL}
1297                 },
1298                 { &stun_att_token,
1299                   { "Token",    "stun.att.token",       FT_BYTES,
1300                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1301                 },
1302                 { &stun_att_value,
1303                   { "Value",    "stun.value",   FT_BYTES,
1304                     BASE_NONE,  NULL,   0x0,    NULL,   HFILL }
1305                 },
1306                 { &stun_att_reserved,
1307                   { "Reserved", "stun.att.reserved",    FT_UINT16,
1308                     BASE_DEC,   NULL,   0x0,    NULL,   HFILL }
1309                 },
1310                 { &stun_att_transp,
1311                   { "Transport",        "stun.att.transp",      FT_UINT8,
1312                     BASE_HEX,   VALS(transportnames),   0x0,    NULL,   HFILL }
1313                 },
1314                 { &stun_att_channelnum,
1315                   { "Channel-Number",   "stun.att.channelnum",  FT_UINT16,
1316                     BASE_HEX,   NULL,   0x0,    NULL,   HFILL }
1317                 },
1318                 { &stun_att_bandwidth,
1319                   { "Bandwidth",        "stun.port.bandwidth",  FT_UINT32,
1320                     BASE_DEC,   NULL,   0x0,    NULL, HFILL }
1321                 },
1322         };
1323
1324         /* Setup protocol subtree array */
1325         static gint *ett[] = {
1326                 &ett_stun,
1327                 &ett_stun_type,
1328                 &ett_stun_att_all,
1329                 &ett_stun_att,
1330                 &ett_stun_att_type,
1331         };
1332
1333         /* Register the protocol name and description */
1334         proto_stun = proto_register_protocol("Session Traversal Utilities for NAT", "STUN", "stun");
1335
1336         /* Required function calls to register the header fields and subtrees used */
1337         proto_register_field_array(proto_stun, hf, array_length(hf));
1338         proto_register_subtree_array(ett, array_length(ett));
1339
1340         /* heuristic subdissectors (used for the DATA field) */
1341         register_heur_dissector_list("stun", &heur_subdissector_list);
1342 }
1343
1344 void
1345 proto_reg_handoff_stun(void)
1346 {
1347         dissector_handle_t stun_tcp_handle;
1348         dissector_handle_t stun_udp_handle;
1349
1350         stun_tcp_handle = create_dissector_handle(dissect_stun_tcp, proto_stun);
1351         stun_udp_handle = new_create_dissector_handle(dissect_stun_udp, proto_stun);
1352
1353         dissector_add("tcp.port", TCP_PORT_STUN, stun_tcp_handle);
1354         dissector_add("udp.port", UDP_PORT_STUN, stun_udp_handle);
1355
1356         heur_dissector_add("udp", dissect_stun_heur, proto_stun);
1357         heur_dissector_add("tcp", dissect_stun_heur, proto_stun);
1358         heur_dissector_add("stun", dissect_stun_heur, proto_stun);
1359
1360         data_handle = find_dissector("data");
1361 }
1362