Temporary patch for the packet_list column resize problem in gtk2.
[obnox/wireshark/wip.git] / 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: packet-stun.c,v 1.3 2003/09/05 04:39:19 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
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  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include <glib.h>
37
38 #ifdef NEED_SNPRINTF_H
39 # include "snprintf.h"
40 #endif
41
42 #include <epan/packet.h>
43
44 /* Initialize the protocol and registered fields */
45 static int proto_stun = -1;
46
47 static int hf_stun_type = -1;           /* STUN message header */
48 static int hf_stun_length = -1;
49 static int hf_stun_id = -1;
50 static int hf_stun_att = -1;
51
52 static int stun_att_type = -1;          /* STUN attribute fields */
53 static int stun_att_length = -1;
54 static int stun_att_value = -1;
55 static int stun_att_family = -1;
56 static int stun_att_ip = -1;
57 static int stun_att_port = -1;
58 static int stun_att_change_ip = -1;
59 static int stun_att_change_port = -1;
60 static int stun_att_unknown = -1;
61 static int stun_att_error_class = -1;
62 static int stun_att_error_number = -1;
63 static int stun_att_error_reason = -1;
64
65
66
67 /* Message Types */
68 #define BINDING_REQUEST                 0x0001
69 #define BINDING_RESPONSE                0x0101
70 #define BINDING_ERROR_RESPONSE          0x0111
71 #define SHARED_SECRET_REQUEST           0x0002
72 #define SHARED_SECRET_RESPONSE          0x0102
73 #define SHARED_SECRET_ERROR_RESPONSE    0x1112
74
75 /* Attribute Types */
76 #define MAPPED_ADDRESS          0x0001
77 #define RESPONSE_ADDRESS        0x0002
78 #define CHANGE_REQUEST          0x0003
79 #define SOURCE_ADDRESS          0x0004
80 #define CHANGED_ADDRESS         0x0005
81 #define USERNAME                0x0006
82 #define PASSWORD                0x0007
83 #define MESSAGE_INTEGRITY       0x0008
84 #define ERROR_CODE              0x0009
85 #define UNKNOWN_ATTRIBUTES      0x000a
86 #define REFLECTED_FROM          0x000b
87
88
89
90 /* Initialize the subtree pointers */
91 static gint ett_stun = -1;
92 static gint ett_stun_att = -1;
93
94
95 #define UDP_PORT_STUN   3478
96 #define TCP_PORT_STUN   3478
97
98
99 #define STUN_HDR_LEN    20      /* STUN message header length */
100 #define ATTR_HDR_LEN    4       /* STUN attribute header length */
101
102
103 static const true_false_string set_flag = {
104         "SET",
105         "NOT SET"
106 };
107
108 static const value_string messages[] = {
109         {BINDING_REQUEST, "Binding Request"},
110         {BINDING_RESPONSE, "Binding Response"},
111         {BINDING_ERROR_RESPONSE, "Binding Error Response"},
112         {SHARED_SECRET_REQUEST, "Shared Secret Request"},
113         {SHARED_SECRET_RESPONSE, "Shared Secret Response"},
114         {SHARED_SECRET_ERROR_RESPONSE, "Shared Secret Error Response"},
115         {0x00, NULL}
116 };
117
118 static const value_string attributes[] = {
119         {MAPPED_ADDRESS, "MAPPED-ADDRESS"},
120         {RESPONSE_ADDRESS, "RESPONSE-ADDRESS"},
121         {CHANGE_REQUEST, "CHANGE-REQUEST"},
122         {SOURCE_ADDRESS, "SOURCE-ADDRESS"},
123         {CHANGED_ADDRESS, "CHANGED-ADDRESS"},
124         {USERNAME, "USERNAME"},
125         {PASSWORD, "PASSWORD"},
126         {MESSAGE_INTEGRITY, "MESSAGE-INTEGRITY"},
127         {ERROR_CODE, "ERROR-CODE"},
128         {REFLECTED_FROM, "REFLECTED-FROM"},
129         {0x00, NULL}
130 };
131
132 static const value_string attributes_family[] = {
133         {0x0001, "IPv4"},
134         {0x00, NULL}
135 };
136
137 static int
138 dissect_stun(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
139 {
140
141         proto_item *ti;
142         proto_item *ta;
143         proto_tree *stun_tree;
144         proto_tree *att_tree;
145         guint16 att_type;
146         guint16 att_length;
147         guint16 offset;
148
149         /*
150          * First check if the frame is really meant for us.
151          */
152
153         /* First, make sure we have enough data to do the check. */
154         if (!tvb_bytes_exist(tvb, 0, STUN_HDR_LEN))
155                 return 0;
156         
157         att_type = tvb_get_ntohs(tvb, 0);
158         
159         /* check if message type is correct */
160         if(     (att_type != BINDING_REQUEST) &&
161                 (att_type != BINDING_RESPONSE) &&
162                 (att_type != BINDING_ERROR_RESPONSE) &&
163                 (att_type != SHARED_SECRET_REQUEST) &&
164                 (att_type != SHARED_SECRET_RESPONSE) &&
165                 (att_type != SHARED_SECRET_ERROR_RESPONSE)
166           )
167                 return 0;
168         
169         
170         att_length = tvb_get_ntohs(tvb, 2);
171         
172         /* check if payload enough */
173         if (!tvb_bytes_exist(tvb, 0, STUN_HDR_LEN+att_length))
174                 return 0;
175
176         if(tvb_bytes_exist(tvb, 0, STUN_HDR_LEN+att_length+1))
177                 return 0;
178
179         /* The message seems to be a valid STUN message! */
180
181         if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
182                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "STUN");
183     
184         if (check_col(pinfo->cinfo, COL_INFO)) {
185                 col_clear(pinfo->cinfo, COL_INFO);
186                 
187                 col_add_fstr(pinfo->cinfo, COL_INFO, "Message : %s",
188                                 (att_type==BINDING_REQUEST)?"Binding Request":
189                                 (att_type==BINDING_RESPONSE)?"Binding Response":
190                                 (att_type==BINDING_ERROR_RESPONSE)?"Binding Error Response":
191                                 (att_type==SHARED_SECRET_REQUEST)?"Shared Secret Request":
192                                 (att_type==SHARED_SECRET_RESPONSE)?"Shared Secret Response":
193                                 (att_type==SHARED_SECRET_ERROR_RESPONSE)?"Shared Secret Error Response":"UNKNOWN"
194                         );
195                             
196         }
197
198
199         if (tree) {
200
201
202                 ti = proto_tree_add_item(tree, proto_stun, tvb, 0, -1, FALSE);
203                             
204                 stun_tree = proto_item_add_subtree(ti, ett_stun);
205
206
207
208
209                 proto_tree_add_item(stun_tree, hf_stun_type, tvb, 0, 2, FALSE);
210                 proto_tree_add_item(stun_tree, hf_stun_length, tvb, 2, 2, FALSE);
211                 proto_tree_add_item(stun_tree, hf_stun_id, tvb, 4, 16, FALSE);
212
213                 ta = proto_tree_add_item(stun_tree, hf_stun_att, tvb, STUN_HDR_LEN, -1, FALSE);
214                 att_tree = proto_item_add_subtree(ta, ett_stun_att);
215
216                 offset = STUN_HDR_LEN;
217
218                 while(1){
219                         if( !tvb_bytes_exist(tvb, offset, ATTR_HDR_LEN) ) /* no data anymore */
220                             break;
221                             
222                         att_type = tvb_get_ntohs(tvb, offset); /* Type field in attribute header */
223                         att_length = tvb_get_ntohs(tvb, offset+2); /* Length field in attribute header */
224                         
225                         
226                         switch( att_type ){
227                                 case MAPPED_ADDRESS:
228                                 case RESPONSE_ADDRESS:
229                                 case SOURCE_ADDRESS:
230                                 case CHANGED_ADDRESS:
231                                 case REFLECTED_FROM:
232                                         proto_tree_add_item(att_tree, stun_att_type, tvb, offset, 2, FALSE);
233                                         proto_tree_add_item(att_tree, stun_att_length, tvb, offset+2, 2, FALSE);
234                                         proto_tree_add_item(att_tree, stun_att_family, tvb, offset+5, 1, FALSE);
235                                         proto_tree_add_item(att_tree, stun_att_port, tvb, offset+6, 2, FALSE);
236                                         proto_tree_add_item(att_tree, stun_att_ip, tvb, offset+8, 4, FALSE);
237
238                                         offset = offset+(ATTR_HDR_LEN+att_length);
239                                         
240                                         break;
241                                         
242                                 case CHANGE_REQUEST:
243                                         proto_tree_add_item(att_tree, stun_att_type, tvb, offset, 2, FALSE);
244                                         proto_tree_add_item(att_tree, stun_att_length, tvb, offset+2, 2, FALSE);
245                                         proto_tree_add_item(att_tree, stun_att_change_ip, tvb, offset+4, 4, FALSE);
246                                         proto_tree_add_item(att_tree, stun_att_change_port, tvb, offset+4, 4, FALSE);
247
248                                         offset = offset+(ATTR_HDR_LEN+att_length);
249                                         
250                                         break;                                  
251                                         
252                                 case USERNAME:
253                                 case PASSWORD:
254                                 case MESSAGE_INTEGRITY:
255                                         proto_tree_add_item(att_tree, stun_att_type, tvb, offset, 2, FALSE);
256                                         proto_tree_add_item(att_tree, stun_att_length, tvb, offset+2, 2, FALSE);
257                                         proto_tree_add_item(att_tree, stun_att_length, tvb, offset+2, att_length, FALSE);
258                                         
259                                         offset = offset+(ATTR_HDR_LEN+att_length);
260                                         
261                                         break;
262                                         
263                                 case ERROR_CODE:
264                                         proto_tree_add_item(att_tree, stun_att_type, tvb, offset, 2, FALSE);
265                                         proto_tree_add_item(att_tree, stun_att_length, tvb, offset+2, 2, FALSE);
266                                         
267                                         proto_tree_add_item(att_tree, stun_att_error_class, tvb, offset+6, 1, FALSE);
268                                         proto_tree_add_item(att_tree, stun_att_error_number, tvb, offset+7, 1, FALSE);
269                                         proto_tree_add_item(att_tree, stun_att_error_reason, tvb, offset+8, (att_length-4), FALSE);
270                                         
271                                         offset = offset+(ATTR_HDR_LEN+att_length);
272                                         
273                                         break;                          
274                                 
275                                 
276                                 case UNKNOWN_ATTRIBUTES:
277                                         proto_tree_add_item(att_tree, stun_att_type, tvb, offset, 2, FALSE);
278                                         proto_tree_add_item(att_tree, stun_att_length, tvb, offset+2, 2, FALSE);
279
280                                         offset = offset + ATTR_HDR_LEN;
281                                         while(tvb_bytes_exist(tvb, offset, 4)){ /* UNKNOWN-ATTRIBUTES is 4 bytes aligned */
282                                                 proto_tree_add_item(att_tree, stun_att_unknown, tvb, offset, 2, FALSE);
283                                                 proto_tree_add_item(att_tree, stun_att_unknown, tvb, offset+2, 2, FALSE);
284                                                 offset = offset + 4;
285                                         }
286                                                         
287                                         break;
288                                         
289                                 default:
290                                         return tvb_length(tvb);
291                                 
292                         }
293                         
294                 }
295         }
296         return tvb_length(tvb);
297 }
298
299
300 static gboolean
301 dissect_stun_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
302 {
303         if (dissect_stun(tvb, pinfo, tree) == 0)
304                 return FALSE;
305
306         return TRUE;
307 }
308
309
310
311
312 void
313 proto_register_stun(void)
314 {
315         static hf_register_info hf[] = {
316                 { &hf_stun_type,
317                         { "Message Type",       "stun.type",    FT_UINT16, 
318                         BASE_HEX,       VALS(messages), 0x0,    "",     HFILL }
319                 },
320                 { &hf_stun_length,
321                         { "Message Length",     "stun.length",  FT_UINT16, 
322                         BASE_HEX,       NULL,   0x0,    "",     HFILL }
323                 },
324                 { &hf_stun_id,
325                         { "Message Transaction ID",     "stun.id",      FT_BYTES,
326                         BASE_HEX,       NULL,   0x0,    "",     HFILL }
327                 },
328                 { &hf_stun_att,
329                         { "Attributes",         "stun.att",     FT_NONE,
330                         0,              NULL,   0x0,    "",     HFILL }
331                 },
332                 /* ////////////////////////////////////// */
333                 { &stun_att_type,
334                         { "Attribute Type",     "stun.att.type",        FT_UINT16,
335                         BASE_HEX,       VALS(attributes),       0x0,    "",     HFILL }
336                 },
337                 { &stun_att_length,
338                         { "Attribute Length",   "stun.att.length",      FT_UINT16,
339                         BASE_DEC,       NULL,   0x0,    "",     HFILL }
340                 },
341                 { &stun_att_value,
342                         { "Value",      "stun.att.value",       FT_BYTES,
343                         BASE_HEX,       NULL,   0x0,    "",     HFILL }
344                 },
345                 { &stun_att_family,
346                         { "Protocol Family",    "stun.att.family",      FT_UINT16,
347                         BASE_HEX,       VALS(attributes_family),        0x0,    "",     HFILL }
348                 },
349                 { &stun_att_ip,
350                         { "IP",         "stun.att.ip",  FT_IPv4,
351                         BASE_NONE,      NULL,   0x0,    "",     HFILL }
352                 },
353                 { &stun_att_port,
354                         { "Port",       "stun.att.port",        FT_UINT16,
355                         BASE_DEC,       NULL,   0x0,    "",     HFILL }
356                 },
357                 { &stun_att_change_ip,
358                         { "Change IP","stun.att.change.ip",     FT_BOOLEAN,
359                         16,     TFS(&set_flag), 0x0004, "",     HFILL}
360                 },
361                 { &stun_att_change_port,
362                         { "Change Port","stun.att.change.port", FT_BOOLEAN,
363                         16,     TFS(&set_flag), 0x0002, "",     HFILL}
364                 },              
365                 { &stun_att_unknown,
366                         { "Unknown Attribute","stun.att.unknown",       FT_UINT16,
367                         BASE_HEX,       NULL,   0x0,    "",     HFILL}
368                 },
369                 { &stun_att_error_class,
370                         { "Error Class","stun.att.error.class", FT_UINT8,
371                         BASE_DEC,       NULL,   0x07,   "",     HFILL}
372                 },
373                 { &stun_att_error_number,
374                         { "Error Code","stun.att.error",        FT_UINT8,
375                         BASE_DEC,       NULL,   0x0,    "",     HFILL}
376                 },
377                 { &stun_att_error_reason,
378                         { "Error Reason Phase","stun.att.error.reason", FT_STRING,
379                         BASE_NONE,      NULL,   0x0,    "",     HFILL}
380                 },
381         };
382
383 /* Setup protocol subtree array */
384         static gint *ett[] = {
385                 &ett_stun,
386                 &ett_stun_att,
387         };
388
389 /* Register the protocol name and description */
390         proto_stun = proto_register_protocol("Simple Traversal of UDP Through NAT",
391             "STUN", "stun");
392
393 /* Required function calls to register the header fields and subtrees used */
394         proto_register_field_array(proto_stun, hf, array_length(hf));
395         proto_register_subtree_array(ett, array_length(ett));
396 }
397
398
399 void
400 proto_reg_handoff_stun(void)
401 {
402         dissector_handle_t stun_handle;
403
404         stun_handle = new_create_dissector_handle(dissect_stun, proto_stun);
405         dissector_add("tcp.port", TCP_PORT_STUN, stun_handle);
406         dissector_add("udp.port", UDP_PORT_STUN, stun_handle);
407
408         heur_dissector_add("udp", dissect_stun_heur, proto_stun);
409         heur_dissector_add("tcp", dissect_stun_heur, proto_stun);
410 }