Don't call "register_all_plugin_handoffs()" if we don't have plugin
[obnox/wireshark/wip.git] / packet-srvloc.c
1 /* packet-srvloc.c
2  * Routines for SRVLOC (Service Location Protocol) packet dissection
3  * Copyright 1999, James Coe <jammer@cin.net>
4  *
5  * NOTE: This is Alpha software not all features have been verified yet.
6  *       In particular I have not had an opportunity to see how it 
7  *       responds to SRVLOC over TCP.
8  *
9  * $Id: packet-srvloc.c,v 1.22 2001/03/09 04:35:22 guy Exp $
10  *
11  * Ethereal - Network traffic analyzer
12  * By Gerald Combs <gerald@zing.org>
13  * Copyright 1998 Gerald Combs
14  *
15  * Service Location Protocol is RFC 2165
16  *
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU General Public License
19  * as published by the Free Software Foundation; either version 2
20  * of the License, or (at your option) any later version.
21  * 
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  * 
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
30  */
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <stdio.h>
37 #include <stdlib.h>
38
39 #ifdef HAVE_SYS_TYPES_H
40 # include <sys/types.h>
41 #endif
42
43 #ifdef HAVE_NETINET_IN_H
44 # include <netinet/in.h>
45 #endif
46
47 #include <string.h>
48 #include <time.h>
49 #include <glib.h>
50
51 #ifdef NEED_SNPRINTF_H
52 # include "snprintf.h"
53 #endif
54
55 #include "packet.h"
56 #include "packet-ipv6.h"
57 #include "strutil.h"
58
59 static int proto_srvloc = -1;
60 static int hf_srvloc_version = -1;
61 static int hf_srvloc_function = -1;
62 static int hf_srvloc_flags = -1;
63 static int hf_srvloc_error = -1;
64
65 static gint ett_srvloc = -1;
66 static gint ett_srvloc_flags = -1;
67
68 #define TCP_PORT_SRVLOC 427
69 #define UDP_PORT_SRVLOC 427
70
71 /* Define function types */
72
73 #define SRVREQ          1
74 #define SRVRPLY         2
75 #define SRVREG          3
76 #define SRVDEREG        4
77 #define SRVACK          5
78 #define ATTRRQST        6
79 #define ATTRRPLY        7
80 #define DAADVERT        8
81 #define SRVTYPERQST     9
82 #define SRVTYPERPLY     10
83
84 /* Create protocol header structure */
85
86 struct srvloc_hdr {
87     guint8      version;
88     guint8      function;
89     guint16     length;
90     guint8      flags;
91     guint8      dialect;
92     u_char      language[2];
93     guint16     encoding;
94     guint16     xid;
95 };
96
97 /* List to resolve function numbers to names */
98
99 static const value_string srvloc_functions[] = {
100     { SRVREQ, "Service Request" }, 
101     { SRVRPLY, "Service Reply" }, 
102     { SRVREG, "Service Registration" }, 
103     { SRVDEREG, "Service Deregister" }, 
104     { SRVACK, "Service Acknowledge" }, 
105     { ATTRRQST, "Attribute Request" }, 
106     { ATTRRPLY, "Attribute Reply" }, 
107     { DAADVERT, "DA Advertisement" }, 
108     { SRVTYPERQST, "Service Type Request" }, 
109     { SRVTYPERPLY, "Service Type Reply" }, 
110     { 0, NULL }
111 };
112
113 /* List to resolve flag values to names */
114
115
116 /* Define flag masks */
117
118 #define FLAG_O          0x80
119 #define FLAG_M          0x40
120 #define FLAG_U          0x20
121 #define FLAG_A          0x10
122 #define FLAG_F          0x08
123
124 /* Define Error Codes */
125
126 #define SUCCESS         0
127 #define LANG_NOT_SPTD   1
128 #define PROT_PARSE_ERR  2
129 #define INVLD_REG       3
130 #define SCOPE_NOT_SPTD  4
131 #define CHRSET_NOT_UND  5
132 #define AUTH_ABSENT     6
133 #define AUTH_FAILED     7
134
135 /* List to resolve error codes to names */
136
137 static const value_string srvloc_errs[] = {
138     { SUCCESS, "No Error" },
139     { LANG_NOT_SPTD, "Language not supported" },
140     { PROT_PARSE_ERR, "Protocol parse error" },
141     { INVLD_REG, "Invalid registration" },
142     { SCOPE_NOT_SPTD, "Scope not supported" },
143     { CHRSET_NOT_UND, "Character set not understood" },
144     { AUTH_ABSENT, "Authentication absent" },
145     { AUTH_FAILED, "Authentication failed" },
146     { 0, NULL }
147 };
148
149 /*
150  * Character encodings.
151  * This is a small subset of what's in
152  *
153  *      http://www.isi.edu/in-notes/iana/assignments/character-sets
154  *
155  * XXX - we should do something useful with this, i.e. properly
156  * handle strings based on the character set they're in.
157  *
158  * XXX - what does "properly handle strings" mean?  How do we know
159  * what character set the terminal can handle (for tty-based code)
160  * or the GUI can handle (for GUI code)?
161  *
162  * XXX - the Ethereal core really should be what does all the
163  * character set handling for strings, and it should be stuck with
164  * the task of figuring out how to properly handle them.
165  */
166 #define CHARSET_ASCII           3
167 #define CHARSET_ISO_10646_UTF_1 27
168 #define CHARSET_ISO_646_BASIC   28
169 #define CHARSET_ISO_646_IRV     30
170 #define CHARSET_ISO_8859_1      4
171 #define CHARSET_ISO_10646_UCS_2 1000    /* a/k/a Unicode */
172 #define CHARSET_UTF_7           1012
173 #define CHARSET_UTF_8           106
174
175 static const value_string charsets[] = {
176         { CHARSET_ASCII, "US-ASCII" },
177         { CHARSET_ISO_10646_UTF_1, "ISO 10646 UTF-1" },
178         { CHARSET_ISO_646_BASIC, "ISO 646 basic:1983" },
179         { CHARSET_ISO_646_IRV, "ISO 646 IRV:1983" },
180         { CHARSET_ISO_8859_1, "ISO 8859-1" },
181         { CHARSET_ISO_10646_UCS_2, "Unicode" },
182         { CHARSET_UTF_7, "UTF-7" },
183         { CHARSET_UTF_8, "UTF-8" },
184         { 0, NULL }
185 };
186
187 static int
188 dissect_authblk(tvbuff_t *tvb, int offset, proto_tree *tree)
189 {
190     struct tm *stamp;
191     time_t seconds;
192     double floatsec;
193     guint16 length;
194     
195     seconds = tvb_get_ntohl(tvb, offset) - 2208988800ul;
196     stamp = gmtime(&seconds);
197     floatsec = stamp->tm_sec + tvb_get_ntohl(tvb, offset + 4) / 4294967296.0;
198     proto_tree_add_text(tree, tvb, offset, 8,
199                         "Timestamp: %04d-%02d-%02d %02d:%02d:%07.4f UTC",
200                         stamp->tm_year + 1900, stamp->tm_mon + 1,
201                         stamp->tm_mday, stamp->tm_hour, stamp->tm_min,
202                         floatsec);
203     proto_tree_add_text(tree, tvb, offset + 8, 2, "Block Structure Desciptor: %u",
204                         tvb_get_ntohs(tvb, offset + 8));
205     length = tvb_get_ntohs(tvb, offset + 10);
206     proto_tree_add_text(tree, tvb, offset + 10, 2, "Authenticator length: %u",
207                         length);
208     offset += 12;
209     proto_tree_add_text(tree, tvb, offset, length, "Authentication block: %s",
210                         tvb_format_text(tvb, offset, length));
211     offset += length;
212     return offset;
213 }
214
215 /* Packet dissection routine called by tcp & udp when port 427 detected */
216
217 static void
218 dissect_srvloc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
219 {
220     int offset = 0;
221     proto_item *ti, *tf;
222     proto_tree *srvloc_tree, *srvloc_flags;
223     guint8 version;
224     guint8 function;
225     guint16 encoding;
226     guint16 length;
227     guint8 flags;
228     guint32 count;
229
230     if (check_col(pinfo->fd, COL_PROTOCOL))
231         col_set_str(pinfo->fd, COL_PROTOCOL, "SRVLOC");
232     
233     if (check_col(pinfo->fd, COL_INFO))
234         col_clear(pinfo->fd, COL_INFO);
235
236     version = tvb_get_guint8(tvb, offset);
237     function = tvb_get_guint8(tvb, offset + 1);
238
239     if (check_col(pinfo->fd, COL_INFO))
240         col_add_str(pinfo->fd, COL_INFO,
241             val_to_str(function, srvloc_functions, "Unknown Function (%u)"));
242         
243     if (tree) {
244         ti = proto_tree_add_item(tree, proto_srvloc, tvb, offset,
245                                  tvb_length(tvb), FALSE);
246         srvloc_tree = proto_item_add_subtree(ti, ett_srvloc);
247     
248         proto_tree_add_uint(srvloc_tree, hf_srvloc_version, tvb, offset, 1,
249                             version);
250         proto_tree_add_uint(srvloc_tree, hf_srvloc_function, tvb, offset + 1, 1,
251                             function);
252         length = tvb_get_ntohs(tvb, offset + 2);
253         proto_tree_add_text(srvloc_tree, tvb, offset + 2, 2, "Length: %u",
254                             length);
255         flags = tvb_get_guint8(tvb, offset + 4);
256         tf = proto_tree_add_uint(srvloc_tree, hf_srvloc_flags, tvb, offset + 4, 1,
257                                  flags);
258         srvloc_flags = proto_item_add_subtree(tf, ett_srvloc_flags);
259         proto_tree_add_text(srvloc_flags, tvb, offset + 4, 0, "Overflow                          %d... .xxx", (flags & FLAG_O) >> 7 );
260         proto_tree_add_text(srvloc_flags, tvb, offset + 4, 0, "Monolingual                       .%d.. .xxx", (flags & FLAG_M) >> 6 );
261         proto_tree_add_text(srvloc_flags, tvb, offset + 4, 0, "URL Authentication Present        ..%d. .xxx", (flags & FLAG_U) >> 5 );
262         proto_tree_add_text(srvloc_flags, tvb, offset + 4, 0, "Attribute Authentication Present  ...%d .xxx", (flags & FLAG_A) >> 4 );
263         proto_tree_add_text(srvloc_flags, tvb, offset + 4, 0, "Fresh Service Entry               .... %dxxx", (flags & FLAG_F) >> 3 );
264         proto_tree_add_text(srvloc_tree, tvb, offset + 5, 1, "Dialect: %u",
265                             tvb_get_guint8(tvb, offset + 5));
266         proto_tree_add_text(srvloc_tree, tvb, offset + 6, 2, "Language: %s",
267                             tvb_format_text(tvb, offset + 6, 2));
268         encoding = tvb_get_ntohs(tvb, offset + 8);
269         proto_tree_add_text(srvloc_tree, tvb, offset + 8, 2, "Encoding: %u (%s)",
270                             encoding,
271                             val_to_str(encoding, charsets, "Unknown"));
272         proto_tree_add_text(srvloc_tree, tvb, offset + 10, 2, "Transaction ID: %u",
273                             tvb_get_ntohs(tvb, offset + 10));
274         offset += 12;
275         
276         switch (function) {
277             case SRVREQ:
278                 proto_tree_add_text(srvloc_tree, tvb, offset, 0, "Service Request");
279                 length = tvb_get_ntohs(tvb, offset);
280                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Previous Response List Length: %u",
281                                     length);
282                 offset += 2;
283                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Previous Response List: %s",
284                                     tvb_format_text(tvb, offset, length));
285                 offset += length;
286                 length = tvb_get_ntohs(tvb, offset);
287                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Predicate length: %u",
288                                     length);
289                 offset += 2;
290                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Predicate: %s",
291                                     tvb_format_text(tvb, offset, length));
292                 offset += length;
293             break;
294             
295             case SRVRPLY:
296                 proto_tree_add_text(srvloc_tree, tvb, offset, 0, "Service Reply");
297                 proto_tree_add_item(srvloc_tree, hf_srvloc_error, tvb, offset, 2, FALSE);
298                 offset += 2;
299                 count = tvb_get_ntohs(tvb, offset);
300                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "URL Count: %u",
301                                     count);
302                 offset += 2;
303                 while (count > 0) {
304                     proto_tree_add_text(srvloc_tree, tvb, offset, 2, "URL lifetime: %u",
305                                         tvb_get_ntohs(tvb, offset));
306                     offset += 2;
307                     length = tvb_get_ntohs(tvb, offset);
308                     proto_tree_add_text(srvloc_tree, tvb, offset, 2, "URL length: %u",
309                                         length);
310                     offset += 2;
311                     proto_tree_add_text(srvloc_tree, tvb, offset, length, "Service URL: %s",
312                                         tvb_format_text(tvb, offset, length));
313                     offset += length;
314                     if ( (flags & FLAG_U) == FLAG_U ) 
315                         offset = dissect_authblk(tvb, offset, srvloc_tree);
316                     count--;
317                 };
318             break;
319
320             case SRVREG:
321                 proto_tree_add_text(srvloc_tree, tvb, offset, 0, "Service Registration");
322                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "URL lifetime: %u",
323                                     tvb_get_ntohs(tvb, offset));
324                 offset += 2;
325                 length = tvb_get_ntohs(tvb, offset);
326                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "URL length: %u",
327                                     length);
328                 offset += 2;
329                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Service URL: %s",
330                                     tvb_format_text(tvb, offset, length));
331                 offset += length;
332                 if ( (flags & FLAG_U) == FLAG_U ) 
333                     offset = dissect_authblk(tvb, offset, srvloc_tree);
334                 length = tvb_get_ntohs(tvb, offset);
335                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Attribute List length: %u",
336                                     length);
337                 offset += 2;
338                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Attribute List: %s",
339                                     tvb_format_text(tvb, offset, length));
340                 offset += length;
341                 if ( (flags & FLAG_A) == FLAG_A ) 
342                     offset = dissect_authblk(tvb, offset, srvloc_tree);
343             break;
344
345             case SRVDEREG:
346                 proto_tree_add_text(srvloc_tree, tvb, offset, 0, "Service Deregister");
347                 length = tvb_get_ntohs(tvb, offset);
348                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "URL length: %u",
349                                     length);
350                 offset += 2;
351                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Service URL: %s",
352                                     tvb_format_text(tvb, offset, length));
353                 offset += length;
354                 if ( (flags & FLAG_U) == FLAG_U ) 
355                     offset = dissect_authblk(tvb, offset, srvloc_tree);
356                 length = tvb_get_ntohs(tvb, offset);
357                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Attribute List length: %u",
358                                     length);
359                 offset += 2;
360                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Attribute List: %s",
361                                     tvb_format_text(tvb, offset, length));
362                 offset += length;
363                 if ( (flags & FLAG_A) == FLAG_A ) 
364                     offset = dissect_authblk(tvb, offset, srvloc_tree);
365             break;
366             
367             case SRVACK:
368                 proto_tree_add_text(srvloc_tree, tvb, offset, 0, "Service Acknowledge");
369                 proto_tree_add_item(srvloc_tree, hf_srvloc_error, tvb, offset, 2, FALSE);
370                 offset += 2;
371             break;
372
373             case ATTRRQST:
374                 proto_tree_add_text(srvloc_tree, tvb, offset, 0, "Attribute Request");
375                 length = tvb_get_ntohs(tvb, offset);
376                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Previous Response List Length: %u",
377                                     length);
378                 offset += 2;
379                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Previous Response List: %s",
380                                     tvb_format_text(tvb, offset, length));
381                 offset += length;
382                 length = tvb_get_ntohs(tvb, offset);
383                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "URL length: %u",
384                                     length);
385                 offset += 2;
386                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Service URL: %s",
387                                     tvb_format_text(tvb, offset, length));
388                 offset += length;
389                 length = tvb_get_ntohs(tvb, offset);
390                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Scope List Length: %u",
391                                     length);
392                 offset += 2;
393                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Scope Response List: %s",
394                                     tvb_format_text(tvb, offset, length));
395                 offset += length;
396                 length = tvb_get_ntohs(tvb, offset);
397                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Attribute List length: %u",
398                                     length);
399                 offset += 2;
400                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Attribute List: %s",
401                                     tvb_format_text(tvb, offset, length));
402                 offset += length;
403             break;
404             
405             case ATTRRPLY:
406                 proto_tree_add_text(srvloc_tree, tvb, offset, 0, "Attribute Reply");
407                 proto_tree_add_item(srvloc_tree, hf_srvloc_error, tvb, offset, 2, FALSE);
408                 offset += 2;
409                 length = tvb_get_ntohs(tvb, offset);
410                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Attribute List length: %u",
411                                     length);
412                 offset += 2;
413                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Attribute List: %s",
414                                     tvb_format_text(tvb, offset, length));
415                 offset += length;
416                 if ( (flags & FLAG_A) == FLAG_A ) 
417                     offset = dissect_authblk(tvb, offset, srvloc_tree);
418             break;
419             
420             case DAADVERT:
421                 proto_tree_add_text(srvloc_tree, tvb, offset, 0, "DA Advertisement");
422                 proto_tree_add_item(srvloc_tree, hf_srvloc_error, tvb, offset, 2, FALSE);
423                 offset += 2;
424                 length = tvb_get_ntohs(tvb, offset);
425                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "URL length: %u",
426                                     length);
427                 offset += 2;
428                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Service URL: %s",
429                                     tvb_format_text(tvb, offset, length));
430                 offset += length;
431                 length = tvb_get_ntohs(tvb, offset);
432                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Scope List Length: %u",
433                                     length);
434                 offset += 2;
435                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Scope Response List: %s",
436                                     tvb_format_text(tvb, offset, length));
437                 offset += length;
438             break;
439
440             case SRVTYPERQST:
441                 proto_tree_add_text(srvloc_tree, tvb, offset, 0, "Service Type Request");
442                 length = tvb_get_ntohs(tvb, offset);
443                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Previous Response List Length: %u",
444                                     length);
445                 offset += 2;
446                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Previous Response List: %s",
447                                     tvb_format_text(tvb, offset, length));
448                 offset += length;
449                 length = tvb_get_ntohs(tvb, offset);
450                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Naming Authority List length: %u",
451                                     length);
452                 offset += 2;
453                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Naming Authority List: %s",
454                                     tvb_format_text(tvb, offset, length));
455                 offset += length;
456                 length = tvb_get_ntohs(tvb, offset);
457                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Scope List Length: %u",
458                                     length);
459                 offset += 2;
460                 proto_tree_add_text(srvloc_tree, tvb, offset, length, "Scope Response List: %s",
461                                     tvb_format_text(tvb, offset, length));
462                 offset += length;
463             break;
464
465             case SRVTYPERPLY:
466                 proto_tree_add_text(srvloc_tree, tvb, offset, 0, "Service Type Reply");
467                 proto_tree_add_item(srvloc_tree, hf_srvloc_error, tvb, offset, 2, FALSE);
468                 offset += 2;
469                 count = tvb_get_ntohs(tvb, offset);
470                 proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Service Type Count: %u",
471                                     count);
472                 offset += 2;
473                 while (count > 0) {
474                     length = tvb_get_ntohs(tvb, offset);
475                     proto_tree_add_text(srvloc_tree, tvb, offset, 2, "Service Type List length: %u",
476                                         length);
477                     offset += 2;
478                     proto_tree_add_text(srvloc_tree, tvb, offset, length, "Service Type List: %s",
479                                         tvb_format_text(tvb, offset, length));
480                     offset += length;
481                     count--;
482                 };
483             break;
484
485             default:
486                 proto_tree_add_text(srvloc_tree, tvb, offset, tvb_length_remaining(tvb, offset), "Unknown Function Type");
487         };
488     };
489 }
490
491 /* Register protocol with Ethereal. */
492
493 void
494 proto_register_srvloc(void)
495 {
496     static hf_register_info hf[] = {
497         { &hf_srvloc_version,
498             { "Version",           "srvloc.version",
499             FT_UINT8, BASE_DEC, NULL, 0x0,
500             "" }
501         },
502       
503         {&hf_srvloc_function,
504             {"Function", "srvloc.function", 
505             FT_UINT8, BASE_DEC, VALS(srvloc_functions), 0x0, 
506             ""}
507         },
508
509         {&hf_srvloc_flags,
510             {"Flags", "srvloc.flags", 
511             FT_UINT8, BASE_HEX, NULL, 0x0, 
512             ""}
513         },
514         
515         {&hf_srvloc_error,
516             {"Error Code", "srvloc.err",
517             FT_UINT16, BASE_DEC, VALS(srvloc_errs), 0x0,
518             ""}
519         },
520     };
521                   
522     static gint *ett[] = {
523         &ett_srvloc,
524         &ett_srvloc_flags,
525     };
526
527     proto_srvloc = proto_register_protocol("Service Location Protocol",
528                                            "SRVLOC", "srvloc");
529     proto_register_field_array(proto_srvloc, hf, array_length(hf));
530     proto_register_subtree_array(ett, array_length(ett));
531 };
532
533 void
534 proto_reg_handoff_srvloc(void)
535 {
536     dissector_add("tcp.port", TCP_PORT_SRVLOC, dissect_srvloc, proto_srvloc);
537     dissector_add("udp.port", UDP_PORT_SRVLOC, dissect_srvloc, proto_srvloc);
538 }
539