packet-stun2 registers for TCP & UDP port 3478 so packet-stun need not register for...
[obnox/wireshark/wip.git] / epan / dissectors / packet-stun.c
1 /* packet-stun.c
2  * Routines for Simple Traversal of UDP Through NAT dissection
3  * Copyright 2003, Shiang-Ming Huang <smhuang@pcs.csie.nctu.edu.tw>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  *
25  * Please refer to RFC 3489 for protocol detail.
26  * (supports extra message attributes described in draft-ietf-behave-rfc3489bis-00)
27  */
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include <glib.h>
38
39 #include <epan/packet.h>
40 #include <epan/conversation.h>
41
42 /* Initialize the protocol and registered fields */
43 static int proto_stun = -1;
44
45 static int hf_stun_type = -1;           /* STUN message header */
46 static int hf_stun_length = -1;
47 static int hf_stun_id = -1;
48 static int hf_stun_att = -1;
49 static int hf_stun_response_in = -1;
50 static int hf_stun_response_to = -1;
51 static int hf_stun_time = -1;
52
53
54 static int stun_att_type = -1;          /* STUN attribute fields */
55 static int stun_att_length = -1;
56 static int stun_att_value = -1;
57 static int stun_att_family = -1;
58 static int stun_att_ipv4 = -1;
59 static int stun_att_ipv6 = -1;
60 static int stun_att_port = -1;
61 static int stun_att_change_ip = -1;
62 static int stun_att_change_port = -1;
63 static int stun_att_unknown = -1;
64 static int stun_att_error_class = -1;
65 static int stun_att_error_number = -1;
66 static int stun_att_error_reason = -1;
67 static int stun_att_server_string = -1;
68 static int stun_att_xor_ipv4 = -1;
69 static int stun_att_xor_ipv6 = -1;
70 static int stun_att_xor_port = -1;
71 static int stun_att_lifetime = -1;
72 static int stun_att_magic_cookie = -1;
73 static int stun_att_bandwidth = -1;
74 static int stun_att_data = -1;
75 static int stun_att_connection_request_binding = -1;
76
77 /* Structure containing transaction specific information */
78 typedef struct _stun_transaction_t {
79         guint32 req_frame;
80         guint32 rep_frame;
81         nstime_t req_time;
82 } stun_transaction_t;
83
84 /* Structure containing conversation specific information */
85 typedef struct _stun_conv_info_t {
86         emem_tree_t *pdus;
87 } stun_conv_info_t;
88
89
90 /* Message Types */
91 #define BINDING_REQUEST                 0x0001
92 #define BINDING_RESPONSE                0x0101
93 #define BINDING_ERROR_RESPONSE          0x0111
94 #define SHARED_SECRET_REQUEST           0x0002
95 #define SHARED_SECRET_RESPONSE          0x0102
96 #define SHARED_SECRET_ERROR_RESPONSE    0x1112
97 #define ALLOCATE_REQUEST                0x0003
98 #define ALLOCATE_RESPONSE               0x0103
99 #define ALLOCATE_ERROR_RESPONSE         0x0113
100 #define SEND_REQUEST                    0x0004
101 #define SEND_RESPONSE                   0x0104
102 #define SEND_ERROR_RESPONSE             0x0114
103 #define DATA_INDICATION                 0x0115
104 #define SET_ACTIVE_DESTINATION_REQUEST  0x0006
105 #define SET_ACTIVE_DESTINATION_RESPONSE 0x0106
106 #define SET_ACTIVE_DESTINATION_ERROR_RESPONSE   0x0116
107
108
109 /* Message classes */
110 #define CLASS_MASK      0xC110
111 #define REQUEST         0x0000
112 #define INDICATION      0x0001
113 #define RESPONSE        0x0010
114 #define ERROR_RESPONSE  0x0011    
115
116 /* Attribute Types */
117 #define MAPPED_ADDRESS          0x0001
118 #define RESPONSE_ADDRESS        0x0002
119 #define CHANGE_REQUEST          0x0003
120 #define SOURCE_ADDRESS          0x0004
121 #define CHANGED_ADDRESS         0x0005
122 #define USERNAME                0x0006
123 #define PASSWORD                0x0007
124 #define MESSAGE_INTEGRITY       0x0008
125 #define ERROR_CODE              0x0009
126 #define UNKNOWN_ATTRIBUTES      0x000a
127 #define REFLECTED_FROM          0x000b
128 #define LIFETIME                0x000d
129 #define ALTERNATE_SERVER        0x000e
130 #define MAGIC_COOKIE            0x000f
131 #define BANDWIDTH               0x0010
132 #define DESTINATION_ADDRESS     0x0011
133 #define REMOTE_ADDRESS          0x0012
134 #define DATA                    0x0013
135 #define NONCE                   0x0014
136 #define REALM                   0x0015
137 #define REQUESTED_ADDRESS_TYPE  0x0016
138 #define XOR_MAPPED_ADDRESS      0x8020
139 #define XOR_ONLY                0x0021
140 #define SERVER                  0x8022
141 #define CONNECTION_REQUEST_BINDING      0xc001
142 #define BINDING_CHANGE                  0xc002
143
144
145
146 /* Initialize the subtree pointers */
147 static gint ett_stun = -1;
148 static gint ett_stun_att_type = -1;
149 static gint ett_stun_att = -1;
150
151
152 #define UDP_PORT_STUN   3478
153 #define TCP_PORT_STUN   3478
154
155
156 #define STUN_HDR_LEN    ((guint)20)     /* STUN message header length */
157 #define ATTR_HDR_LEN    4       /* STUN attribute header length */
158
159
160 static const true_false_string set_flag = {
161         "SET",
162         "NOT SET"
163 };
164
165 static const value_string messages[] = {
166         {BINDING_REQUEST, "Binding Request"},
167         {BINDING_RESPONSE, "Binding Response"},
168         {BINDING_ERROR_RESPONSE, "Binding Error Response"},
169         {SHARED_SECRET_REQUEST, "Shared Secret Request"},
170         {SHARED_SECRET_RESPONSE, "Shared Secret Response"},
171         {SHARED_SECRET_ERROR_RESPONSE, "Shared Secret Error Response"},
172         {ALLOCATE_REQUEST, "Allocate Request"},
173         {ALLOCATE_RESPONSE, "Allocate Response"},
174         {ALLOCATE_ERROR_RESPONSE, "Allocate Error Response"},
175         {SEND_REQUEST, "Send Request"},
176         {SEND_RESPONSE, "Send Response"},
177         {SEND_ERROR_RESPONSE, "Send Error Response"},
178         {DATA_INDICATION, "Data Indication"},
179         {SET_ACTIVE_DESTINATION_REQUEST, "Set Active Destination Request"},
180         {SET_ACTIVE_DESTINATION_RESPONSE, "Set Active Destination Response"},
181         {SET_ACTIVE_DESTINATION_ERROR_RESPONSE, "Set Active Destination Error Response"},
182         {0x00, NULL}
183 };
184
185 static const value_string attributes[] = {
186         {MAPPED_ADDRESS, "MAPPED-ADDRESS"},
187         {RESPONSE_ADDRESS, "RESPONSE-ADDRESS"},
188         {CHANGE_REQUEST, "CHANGE-REQUEST"},
189         {SOURCE_ADDRESS, "SOURCE-ADDRESS"},
190         {CHANGED_ADDRESS, "CHANGED-ADDRESS"},
191         {USERNAME, "USERNAME"},
192         {PASSWORD, "PASSWORD"},
193         {MESSAGE_INTEGRITY, "MESSAGE-INTEGRITY"},
194         {ERROR_CODE, "ERROR-CODE"},
195         {REFLECTED_FROM, "REFLECTED-FROM"},
196         {LIFETIME, "LIFETIME"},
197         {ALTERNATE_SERVER, "ALTERNATE_SERVER"},
198         {MAGIC_COOKIE, "MAGIC_COOKIE"},
199         {BANDWIDTH, "BANDWIDTH"},
200         {DESTINATION_ADDRESS, "DESTINATION_ADDRESS"},
201         {REMOTE_ADDRESS, "REMOTE_ADDRESS"},
202         {DATA, "DATA"},
203         {NONCE, "NONCE"},
204         {REALM, "REALM"},
205         {REQUESTED_ADDRESS_TYPE, "REQUESTED_ADDRESS_TYPE"},
206         {XOR_MAPPED_ADDRESS, "XOR_MAPPED_ADDRESS"},
207         {XOR_ONLY, "XOR_ONLY"},
208         {SERVER, "SERVER"},
209         {CONNECTION_REQUEST_BINDING, "CONNECTION-REQUEST-BINDING"},
210         {BINDING_CHANGE, "BINDING-CHANGE"},
211         {0x00, NULL}
212 };
213
214 static const value_string attributes_family[] = {
215         {0x0001, "IPv4"},
216         {0x0002, "IPv6"},
217         {0x00, NULL}
218 };
219
220 static int
221 dissect_stun(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
222 {
223
224         proto_item *ti;
225         proto_item *ta;
226         proto_tree *stun_tree;
227         proto_tree *att_type_tree;
228         proto_tree *att_tree;
229         guint16 msg_type;
230         guint16 msg_length;
231         const char *msg_type_str;
232         guint16 att_type;
233         guint16 att_length;
234         guint16 offset;
235         guint   len;
236         guint i;
237         conversation_t *conversation;
238         stun_conv_info_t *stun_info;
239         stun_transaction_t * stun_trans;
240         emem_tree_key_t transaction_id_key[2];
241         guint32 transaction_id[4];
242
243
244         /*
245          * First check if the frame is really meant for us.
246          */
247         len = tvb_length(tvb);
248         /* First, make sure we have enough data to do the check. */
249         if (len < STUN_HDR_LEN)
250                 return 0;
251         
252         msg_type = tvb_get_ntohs(tvb, 0);
253
254         if (msg_type & 0xC000 || tvb_get_ntohl(tvb, 4) == 0x2112a442)
255                 return 0;
256         
257         /* check if message type is correct */
258         msg_type_str = match_strval(msg_type, messages);
259         if (msg_type_str == NULL)
260                 return 0;
261         
262         msg_length = tvb_get_ntohs(tvb, 2);
263         
264         /* check if payload enough */
265         if (len != STUN_HDR_LEN+msg_length)
266                 return 0;
267
268         /* The message seems to be a valid STUN message! */
269
270         /* Create the transaction key which may be used
271            to track the conversation */
272         transaction_id[0] = tvb_get_ntohl(tvb, 4);
273         transaction_id[1] = tvb_get_ntohl(tvb, 8);
274         transaction_id[2] = tvb_get_ntohl(tvb, 12);
275         transaction_id[3] = tvb_get_ntohl(tvb, 16);
276
277         transaction_id_key[0].length = 4;
278         transaction_id_key[0].key =  transaction_id;
279         transaction_id_key[1].length = 0;
280         transaction_id_key[1].key =  NULL;
281
282         /*
283          * Do we have a conversation for this connection?
284          */
285         conversation = find_conversation(pinfo->fd->num, 
286                                          &pinfo->src, &pinfo->dst,
287                                          pinfo->ptype, 
288                                          pinfo->srcport, pinfo->destport, 0);
289         if (conversation == NULL) {
290           /* We don't yet have a conversation, so create one. */
291           conversation = conversation_new(pinfo->fd->num, 
292                                           &pinfo->src, &pinfo->dst,
293                                           pinfo->ptype,
294                                           pinfo->srcport, pinfo->destport, 0);
295         }
296         /*
297          * Do we already have a state structure for this conv
298          */
299         stun_info = conversation_get_proto_data(conversation, proto_stun);
300         if (!stun_info) {
301           /* No.  Attach that information to the conversation, and add
302            * it to the list of information structures.
303            */
304           stun_info = se_alloc(sizeof(stun_conv_info_t));
305           stun_info->pdus=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "stun_pdus");
306           conversation_add_proto_data(conversation, proto_stun, stun_info);
307         }
308         
309         if(!pinfo->fd->flags.visited){
310           if (((msg_type & CLASS_MASK) >> 4) == REQUEST) {
311             /* This is a request */
312             stun_trans=se_alloc(sizeof(stun_transaction_t));
313             stun_trans->req_frame=pinfo->fd->num;
314             stun_trans->rep_frame=0;
315             stun_trans->req_time=pinfo->fd->abs_ts;
316             se_tree_insert32_array(stun_info->pdus, transaction_id_key, 
317                                   (void *)stun_trans);
318           } else {
319             stun_trans=se_tree_lookup32_array(stun_info->pdus, 
320                                                transaction_id_key);
321             if(stun_trans){
322               stun_trans->rep_frame=pinfo->fd->num;
323             }
324           }
325         } else {
326           stun_trans=se_tree_lookup32_array(stun_info->pdus, transaction_id_key);
327         }
328         if(!stun_trans){
329           /* create a "fake" pana_trans structure */
330           stun_trans=ep_alloc(sizeof(stun_transaction_t));
331           stun_trans->req_frame=0;
332           stun_trans->rep_frame=0;
333           stun_trans->req_time=pinfo->fd->abs_ts;
334         }
335         
336
337
338         if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
339                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "STUN");
340     
341         if (check_col(pinfo->cinfo, COL_INFO)) {
342                 col_add_fstr(pinfo->cinfo, COL_INFO, "Message: %s",
343                     msg_type_str);
344         }
345
346         if (tree) {
347                 guint transaction_id_first_word;
348
349                 ti = proto_tree_add_item(tree, proto_stun, tvb, 0, -1, FALSE);
350                             
351                 stun_tree = proto_item_add_subtree(ti, ett_stun);
352
353                 if (((msg_type & CLASS_MASK) >> 4) == REQUEST) {
354                   if (stun_trans->rep_frame) {
355                     proto_item *it;
356                     it=proto_tree_add_uint(stun_tree, hf_stun_response_in, 
357                                            tvb, 0, 0, 
358                                            stun_trans->rep_frame);
359                     PROTO_ITEM_SET_GENERATED(it);
360                   }
361                 }
362                 else if ((((msg_type & CLASS_MASK) >> 4) == RESPONSE) ||
363                          (((msg_type & CLASS_MASK) >> 4) == ERROR_RESPONSE)) {
364                   /* This is a response */
365                   if(stun_trans->req_frame){
366                     proto_item *it;
367                     nstime_t ns;
368                     
369                     it=proto_tree_add_uint(stun_tree, hf_stun_response_to, tvb, 0, 0, stun_trans->req_frame);
370                     PROTO_ITEM_SET_GENERATED(it);
371                     
372                     nstime_delta(&ns, &pinfo->fd->abs_ts, &stun_trans->req_time);
373                     it=proto_tree_add_time(stun_tree, hf_stun_time, tvb, 0, 0, &ns);
374                     PROTO_ITEM_SET_GENERATED(it);
375                   }
376                   
377                 }
378
379                 proto_tree_add_uint(stun_tree, hf_stun_type, tvb, 0, 2, msg_type);
380                 proto_tree_add_uint(stun_tree, hf_stun_length, tvb, 2, 2, msg_length);
381                 proto_tree_add_item(stun_tree, hf_stun_id, tvb, 4, 16, FALSE);
382
383                 /* Remember this (in host order) so we can show clear xor'd addresses */
384                 transaction_id_first_word = tvb_get_ntohl(tvb, 4);
385
386                 if (msg_length > 0) {
387                     ta = proto_tree_add_item(stun_tree, hf_stun_att, tvb, STUN_HDR_LEN, msg_length, FALSE);
388                     att_type_tree = proto_item_add_subtree(ta, ett_stun_att_type);
389
390                     offset = STUN_HDR_LEN;
391
392                     while( msg_length > 0) {
393                         att_type = tvb_get_ntohs(tvb, offset); /* Type field in attribute header */
394                         att_length = tvb_get_ntohs(tvb, offset+2); /* Length field in attribute header */
395                         
396                         ta = proto_tree_add_text(att_type_tree, tvb, offset,
397                             ATTR_HDR_LEN+att_length,
398                             "Attribute: %s",
399                             val_to_str(att_type, attributes, "Unknown (0x%04x)"));
400                         att_tree = proto_item_add_subtree(ta, ett_stun_att);
401                         
402                         proto_tree_add_uint(att_tree, stun_att_type, tvb,
403                             offset, 2, att_type);
404                         offset += 2;
405                         if (ATTR_HDR_LEN+att_length > msg_length) {
406                                 proto_tree_add_uint_format(att_tree,
407                                     stun_att_length, tvb, offset, 2,
408                                     att_length,
409                                     "Attribute Length: %u (bogus, goes past the end of the message)",
410                                     att_length);
411                                 break;
412                         }
413                         proto_tree_add_uint(att_tree, stun_att_length, tvb,
414                             offset, 2, att_length);
415                         offset += 2;
416                         switch( att_type ){
417                                 case MAPPED_ADDRESS:
418                                 case RESPONSE_ADDRESS:
419                                 case SOURCE_ADDRESS:
420                                 case CHANGED_ADDRESS:
421                                 case REFLECTED_FROM:
422                                 case ALTERNATE_SERVER:
423                                 case DESTINATION_ADDRESS:
424                                 case REMOTE_ADDRESS:
425                                         if (att_length < 2)
426                                                 break;
427                                         proto_tree_add_item(att_tree, stun_att_family, tvb, offset+1, 1, FALSE);
428                                         if (att_length < 4)
429                                                 break;
430                                         proto_tree_add_item(att_tree, stun_att_port, tvb, offset+2, 2, FALSE);
431                                         switch( tvb_get_guint8(tvb, offset+1) ){
432                                                 case 1:
433                                                         if (att_length < 8)
434                                                                 break;
435                                                         proto_tree_add_item(att_tree, stun_att_ipv4, tvb, offset+4, 4, FALSE);
436                                                         break;
437
438                                                 case 2:
439                                                         if (att_length < 20)
440                                                                 break;
441                                                         proto_tree_add_item(att_tree, stun_att_ipv6, tvb, offset+4, 16, FALSE);
442                                                         break;
443                                                 }
444                                         break;
445                                         
446                                 case CHANGE_REQUEST:
447                                         if (att_length < 4)
448                                                 break;
449                                         proto_tree_add_item(att_tree, stun_att_change_ip, tvb, offset, 4, FALSE);
450                                         proto_tree_add_item(att_tree, stun_att_change_port, tvb, offset, 4, FALSE);
451                                         break;                                  
452                                         
453                                 case USERNAME:
454                                 case PASSWORD:
455                                 case MESSAGE_INTEGRITY:
456                                 case NONCE:
457                                 case REALM:
458                                         if (att_length < 1)
459                                                 break;
460                                         proto_tree_add_item(att_tree, stun_att_value, tvb, offset, att_length, FALSE);
461                                         break;
462                                         
463                                 case ERROR_CODE:
464                                         if (att_length < 3)
465                                                 break;
466                                         proto_tree_add_item(att_tree, stun_att_error_class, tvb, offset+2, 1, FALSE);
467                                         if (att_length < 4)
468                                                 break;
469                                         proto_tree_add_item(att_tree, stun_att_error_number, tvb, offset+3, 1, FALSE);
470                                         if (att_length < 5)
471                                                 break;
472                                         proto_tree_add_item(att_tree, stun_att_error_reason, tvb, offset+4, (att_length-4), FALSE);
473                                         break;
474                                 
475                                 case LIFETIME:
476                                         if (att_length < 4)
477                                                 break;
478                                         proto_tree_add_item(att_tree, stun_att_lifetime, tvb, offset, 4, FALSE);
479                                         break;
480
481                                 case MAGIC_COOKIE:
482                                         if (att_length < 4)
483                                                 break;
484                                         proto_tree_add_item(att_tree, stun_att_magic_cookie, tvb, offset, 4, FALSE);
485                                         break;
486
487                                 case BANDWIDTH:
488                                         if (att_length < 4)
489                                                 break;
490                                         proto_tree_add_item(att_tree, stun_att_bandwidth, tvb, offset, 4, FALSE);
491                                         break;
492
493                                 case DATA:
494                                         proto_tree_add_item(att_tree, stun_att_data, tvb, offset, att_length, FALSE);
495                                         break;
496
497                                 case UNKNOWN_ATTRIBUTES:
498                                         for (i = 0; i < att_length; i += 4) {
499                                                 proto_tree_add_item(att_tree, stun_att_unknown, tvb, offset+i, 2, FALSE);
500                                                 proto_tree_add_item(att_tree, stun_att_unknown, tvb, offset+i+2, 2, FALSE);
501                                         }
502                                         break;
503                                         
504                                 case SERVER:
505                                         proto_tree_add_item(att_tree, stun_att_server_string, tvb, offset, att_length, FALSE);
506                                         break;
507
508                                 case XOR_MAPPED_ADDRESS:
509                                         if (att_length < 2)
510                                                 break;
511                                         proto_tree_add_item(att_tree, stun_att_family, tvb, offset+1, 1, FALSE);
512                                         if (att_length < 4)
513                                                 break;
514                                         proto_tree_add_item(att_tree, stun_att_xor_port, tvb, offset+2, 2, FALSE);
515
516                                         /* Show the port 'in the clear'
517                                                 XOR (host order) transid with (host order) xor-port.
518                                                 Add host-order port into tree. */
519                                         ti = proto_tree_add_uint(att_tree, stun_att_port, tvb, offset+2, 2,
520                                                                  tvb_get_ntohs(tvb, offset+2) ^
521                                                                  (transaction_id_first_word >> 16));
522                                         PROTO_ITEM_SET_GENERATED(ti);
523
524                                         if (att_length < 8)
525                                                 break;
526                                         switch( tvb_get_guint8(tvb, offset+1) ){
527                                                 case 1:
528                                                         if (att_length < 8)
529                                                                 break;
530                                                         proto_tree_add_item(att_tree, stun_att_xor_ipv4, tvb, offset+4, 4, FALSE);
531
532                                                         /* Show the address 'in the clear'.
533                                                            XOR (host order) transid with (host order) xor-address.
534                                                            Add in network order tree. */
535                                                         ti = proto_tree_add_ipv4(att_tree, stun_att_ipv4, tvb, offset+4, 4,
536                                                                                                          g_htonl(tvb_get_ntohl(tvb, offset+4) ^
537                                                                                                          transaction_id_first_word));
538                                                         PROTO_ITEM_SET_GENERATED(ti);
539                                                         break;
540
541                                                 case 2:
542                                                         if (att_length < 20)
543                                                                 break;
544                                                         proto_tree_add_item(att_tree, stun_att_xor_ipv6, tvb, offset+4, 16, FALSE);
545                                                         break;
546                                                 }
547                                         break;
548
549                                 case REQUESTED_ADDRESS_TYPE:
550                                         if (att_length < 2)
551                                                 break;
552                                         proto_tree_add_item(att_tree, stun_att_family, tvb, offset+1, 1, FALSE);
553                                         break;
554
555                                 case CONNECTION_REQUEST_BINDING:
556                                         proto_tree_add_item(att_tree, stun_att_connection_request_binding, tvb, offset, att_length, FALSE);
557                                         break;                              
558
559                                 default:
560                                         break;
561                         }
562                         offset += att_length;
563                         msg_length -= ATTR_HDR_LEN+att_length;
564                     }
565                 }
566         }
567         return tvb_length(tvb);
568 }
569
570
571 static gboolean
572 dissect_stun_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
573 {
574         if (dissect_stun(tvb, pinfo, tree) == 0)
575                 return FALSE;
576
577         return TRUE;
578 }
579
580
581
582
583 void
584 proto_register_stun(void)
585 {
586         static hf_register_info hf[] = {
587                 { &hf_stun_type,
588                         { "Message Type",       "stun.type",    FT_UINT16, 
589                         BASE_HEX,       VALS(messages), 0x0,    NULL,   HFILL }
590                 },
591                 { &hf_stun_length,
592                         { "Message Length",     "stun.length",  FT_UINT16, 
593                         BASE_HEX,       NULL,   0x0,    NULL,   HFILL }
594                 },
595                 { &hf_stun_id,
596                         { "Message Transaction ID",     "stun.id",      FT_BYTES,
597                         BASE_NONE,      NULL,   0x0,    NULL,   HFILL }
598                 },
599                 { &hf_stun_att,
600                         { "Attributes",         "stun.att",     FT_NONE,
601                         BASE_NONE,              NULL,   0x0,    NULL,   HFILL }
602                 },
603                 { &hf_stun_response_in,
604                   { "Response In", "stun.response_in",
605                     FT_FRAMENUM, BASE_NONE, NULL, 0x0,
606                     "The response to this STUN query is in this frame", HFILL }},
607                 { &hf_stun_response_to,
608                   { "Request In", "stun.response_to",
609                     FT_FRAMENUM, BASE_NONE, NULL, 0x0,
610                     "This is a response to the STUN Request in this frame", HFILL }},
611                 { &hf_stun_time,
612                   { "Time", "stun.time",
613                     FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
614                     "The time between the Request and the Response", HFILL }},
615
616                 /* ////////////////////////////////////// */
617                 { &stun_att_type,
618                         { "Attribute Type",     "stun.att.type",        FT_UINT16,
619                         BASE_HEX,       VALS(attributes),       0x0,    NULL,   HFILL }
620                 },
621                 { &stun_att_length,
622                         { "Attribute Length",   "stun.att.length",      FT_UINT16,
623                         BASE_DEC,       NULL,   0x0,    NULL,   HFILL }
624                 },
625                 { &stun_att_value,
626                         { "Value",      "stun.att.value",       FT_BYTES,
627                         BASE_NONE,      NULL,   0x0,    NULL,   HFILL }
628                 },
629                 { &stun_att_family,
630                         { "Protocol Family",    "stun.att.family",      FT_UINT16,
631                         BASE_HEX,       VALS(attributes_family),        0x0,    NULL,   HFILL }
632                 },
633                 { &stun_att_ipv4,
634                         { "IP",         "stun.att.ipv4",        FT_IPv4,
635                         BASE_NONE,      NULL,   0x0,    NULL,   HFILL }
636                 },
637                 { &stun_att_ipv6,
638                         { "IP",         "stun.att.ipv6",        FT_IPv6,
639                         BASE_NONE,      NULL,   0x0,    NULL,   HFILL }
640                 },
641                 { &stun_att_port,
642                         { "Port",       "stun.att.port",        FT_UINT16,
643                         BASE_DEC,       NULL,   0x0,    NULL,   HFILL }
644                 },
645                 { &stun_att_change_ip,
646                         { "Change IP","stun.att.change.ip",     FT_BOOLEAN,
647                         16,     TFS(&set_flag), 0x0004, NULL,   HFILL}
648                 },
649                 { &stun_att_change_port,
650                         { "Change Port","stun.att.change.port", FT_BOOLEAN,
651                         16,     TFS(&set_flag), 0x0002, NULL,   HFILL}
652                 },              
653                 { &stun_att_unknown,
654                         { "Unknown Attribute","stun.att.unknown",       FT_UINT16,
655                         BASE_HEX,       NULL,   0x0,    NULL,   HFILL}
656                 },
657                 { &stun_att_error_class,
658                         { "Error Class","stun.att.error.class", FT_UINT8,
659                         BASE_DEC,       NULL,   0x07,   NULL,   HFILL}
660                 },
661                 { &stun_att_error_number,
662                         { "Error Code","stun.att.error",        FT_UINT8,
663                         BASE_DEC,       NULL,   0x0,    NULL,   HFILL}
664                 },
665                 { &stun_att_error_reason,
666                         { "Error Reason Phase","stun.att.error.reason", FT_STRING,
667                         BASE_NONE,      NULL,   0x0,    NULL,   HFILL}
668                 },
669                 { &stun_att_xor_ipv4,
670                         { "IP (XOR-d)",         "stun.att.ipv4-xord",   FT_IPv4,
671                         BASE_NONE,      NULL,   0x0,    NULL,   HFILL }
672                 },
673                 { &stun_att_xor_ipv6,
674                         { "IP (XOR-d)",         "stun.att.ipv6-xord",   FT_IPv6,
675                         BASE_NONE,      NULL,   0x0,    NULL,   HFILL }
676                 },
677                 { &stun_att_xor_port,
678                         { "Port (XOR-d)",       "stun.att.port-xord",   FT_UINT16,
679                         BASE_DEC,       NULL,   0x0,    NULL,   HFILL }
680                 },
681                 { &stun_att_server_string,
682                         { "Server version","stun.att.server",   FT_STRING,
683                         BASE_NONE,      NULL,   0x0,    NULL,   HFILL}
684                 },
685                 { &stun_att_lifetime,
686                         { "Lifetime",   "stun.att.lifetime",    FT_UINT32,
687                         BASE_DEC,       NULL,   0x0,    NULL,   HFILL }
688                 },
689                 { &stun_att_magic_cookie,
690                         { "Magic Cookie",       "stun.att.magic.cookie",        FT_UINT32,
691                         BASE_HEX,       NULL,   0x0,    NULL,   HFILL }
692                 },
693                 { &stun_att_bandwidth,
694                         { "Bandwidth",  "stun.att.bandwidth",   FT_UINT32,
695                         BASE_DEC,       NULL,   0x0,    NULL,   HFILL }
696                 },
697                 { &stun_att_data,
698                         { "Data",       "stun.att.data",        FT_BYTES,
699                         BASE_NONE,      NULL,   0x0,    NULL,   HFILL }
700                 },
701                 { &stun_att_connection_request_binding,
702                         { "Connection Request Binding", "stun.att.connection_request_binding", FT_STRING,
703                           BASE_NONE,      NULL, 0x0,    NULL,     HFILL }
704                 },
705         };
706
707 /* Setup protocol subtree array */
708         static gint *ett[] = {
709                 &ett_stun,
710                 &ett_stun_att_type,
711                 &ett_stun_att,
712         };
713
714 /* Register the protocol name and description */
715         proto_stun = proto_register_protocol("Simple Traversal of UDP Through NAT",
716             "STUN", "stun");
717
718 /* Required function calls to register the header fields and subtrees used */
719         proto_register_field_array(proto_stun, hf, array_length(hf));
720         proto_register_subtree_array(ett, array_length(ett));
721
722         new_register_dissector("stun", dissect_stun, proto_stun);
723         new_register_dissector("stun-heur", dissect_stun_heur, proto_stun);
724 }
725
726
727 void
728 proto_reg_handoff_stun(void)
729 {
730 #if 0 /* The stun2 dissector registers on these ports */
731         dissector_handle_t stun_handle;
732
733         stun_handle = find_dissector("stun");
734
735         dissector_add("tcp.port", TCP_PORT_STUN, stun_handle);
736         dissector_add("udp.port", UDP_PORT_STUN, stun_handle);
737 #endif
738         heur_dissector_add("udp", dissect_stun_heur, proto_stun);
739         heur_dissector_add("tcp", dissect_stun_heur, proto_stun);
740 }