Don't guard col_set_str (COL_PROTOCOL) with col_check
[obnox/wireshark/wip.git] / epan / dissectors / packet-lwres.c
1 /* packet-lwres.c
2  * Routines for light weight reslover (lwres, part of BIND9) packet disassembly
3  *
4  * $Id$
5  *
6  * Copyright (c) 2003 by Oleg Terletsky <oleg.terletsky@comverse.com>
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1999 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <ctype.h>
34 #include <time.h>
35 #include <string.h>
36
37 #include <glib.h>
38 #include <epan/packet.h>
39 #include <epan/prefs.h>
40
41 #define LWRES_LWPACKET_LENGTH           (4 * 5 + 2 * 4)
42 #define LWRES_LWPACKETFLAG_RESPONSE     0x0001U /* if set, pkt is a response */
43 #define LWRES_LWPACKETVERSION_0         0
44
45 #define LW_LENGTH_OFFSET                0 
46 #define LW_VERSION_OFFSET               4 
47 #define LW_PKTFLASG_OFFSET              6
48 #define LW_SERIAL_OFFSET                8 
49 #define LW_OPCODE_OFFSET                12 
50 #define LW_RESULT_OFFSET                16 
51 #define LW_RECVLEN_OFFSET               20 
52 #define LW_AUTHTYPE_OFFSET              24 
53 #define LW_AUTHLEN_OFFSET               26 
54
55
56 #define LWRES_OPCODE_NOOP               0x00000000U
57 #define LWRES_OPCODE_GETADDRSBYNAME     0x00010001U
58 #define LWRES_OPCODE_GETNAMEBYADDR      0x00010002U
59 #define LWRES_OPCODE_GETRDATABYNAME     0x00010003U
60
61 static const value_string opcode_values[] = {
62         { LWRES_OPCODE_NOOP,                    "Noop" },
63         { LWRES_OPCODE_GETADDRSBYNAME,  "getaddrbyname" },
64         { LWRES_OPCODE_GETNAMEBYADDR,   "getnamebyaddr" },
65         { LWRES_OPCODE_GETRDATABYNAME,  "getrdatabyname" },
66         { 0, NULL },
67 };
68
69
70 #define LWRES_R_SUCCESS                 0
71 #define LWRES_R_NOMEMORY                1
72 #define LWRES_R_TIMEOUT                 2
73 #define LWRES_R_NOTFOUND                3
74 #define LWRES_R_UNEXPECTEDEND           4       /* unexpected end of input */
75 #define LWRES_R_FAILURE                 5       /* generic failure */
76 #define LWRES_R_IOERROR                 6
77 #define LWRES_R_NOTIMPLEMENTED          7
78 #define LWRES_R_UNEXPECTED              8
79 #define LWRES_R_TRAILINGDATA            9
80 #define LWRES_R_INCOMPLETE              10
81 #define LWRES_R_RETRY                   11
82 #define LWRES_R_TYPENOTFOUND            12
83 #define LWRES_R_TOOLARGE                13
84
85 #define T_A             1
86 #define T_NS    2
87 #define T_MX    15
88 #define T_SRV   33
89
90
91 static const value_string t_types[] = {
92         { T_A,          "T_A" },
93         { T_NS,         "T_NS" },
94         { T_MX,         "T_MX" },
95         { T_SRV,        "T_SRV" },
96         { 0,            NULL },
97 };
98         
99
100
101
102 static const value_string result_values[]  = {
103         { LWRES_R_SUCCESS,              "Success" },
104         { LWRES_R_NOMEMORY,             "No memory" },
105         { LWRES_R_TIMEOUT,                      "Timeout" },
106         { LWRES_R_NOTFOUND,                     "Not found" },
107         { LWRES_R_UNEXPECTEDEND,        "Unexpected end of input" },
108         { LWRES_R_FAILURE,                      "Generic failure" },
109         { LWRES_R_IOERROR,                      "I/O Error" },
110         { LWRES_R_UNEXPECTED,           "Unexpected" },
111         { LWRES_R_TRAILINGDATA,         "Trailing data" },
112         { LWRES_R_INCOMPLETE,           "Incomplete" },
113         { LWRES_R_RETRY,                        "Retry" },
114         { LWRES_R_TYPENOTFOUND,         "Type not found" },
115         { LWRES_R_TOOLARGE,                     "Too large" },
116         { 0,                                            NULL },
117 };
118
119 static int hf_length = -1;
120 static int hf_version = -1;
121 static int hf_flags = -1;
122 static int hf_serial = -1;
123 static int hf_opcode = -1;
124 static int hf_result = -1;
125 static int hf_recvlen = -1;
126 static int hf_authtype = -1;
127 static int hf_authlen = -1;
128
129 static int hf_rflags = -1;
130 static int hf_rdclass = -1;
131 static int hf_rdtype = -1;
132 static int hf_namelen = -1;
133 static int hf_req_name = -1;
134
135 static int hf_ttl = -1;
136 static int hf_nrdatas = -1;
137 static int hf_nsigs = -1;
138 static int hf_realnamelen = -1;
139 static int hf_realname = -1;
140
141
142 static int hf_a_record = -1;
143 static int hf_a_rec_len = -1;
144 static int hf_srv_prio = -1;
145 static int hf_srv_weight = -1;
146 static int hf_srv_port = -1;
147
148 static int hf_adn_flags = -1;
149 static int hf_adn_addrtype = -1;
150 static int hf_adn_namelen = -1;
151 static int hf_adn_name = -1;
152
153 static int hf_adn_realname = -1;
154 static int hf_adn_aliasname = -1;
155
156 static int hf_adn_naddrs = -1;
157 static int hf_adn_naliases = -1;
158 static int hf_adn_family = -1;
159 static int hf_adn_addr_len = -1;
160 static int hf_adn_addr_addr = -1;
161
162
163 static int ett_lwres = -1;
164 static int ett_rdata_req = -1;
165 static int ett_rdata_resp = -1;
166 static int ett_a_rec = -1;
167 static int ett_a_rec_addr = -1;
168 static int ett_srv_rec = -1;
169 static int ett_srv_rec_item = -1;
170 static int ett_adn_request = -1;
171 static int ett_adn_resp = -1;
172 static int ett_adn_alias = -1;
173 static int ett_adn_addr = -1;
174 static int ett_nba_request = -1;
175 static int ett_nba_resp = -1;
176 static int ett_noop = -1;
177
178 static int ett_mx_rec = -1;
179 static int ett_mx_rec_item = -1;
180
181 static int ett_ns_rec = -1;
182 static int ett_ns_rec_item = -1;
183
184
185
186 #define LWRES_UDP_PORT 921
187
188 static guint global_lwres_port = LWRES_UDP_PORT;
189
190 void proto_reg_handoff_lwres(void);
191
192
193 /* Define the lwres proto */
194 static int proto_lwres = -1;
195
196
197 /* Define many many headers for mgcp */
198
199 static const value_string message_types_values[] = {
200     { 1,          "REQUEST " },
201     { 2,          "RESPONSE" },
202     { 0 ,                       NULL },
203 };
204
205
206
207 static int
208 lwres_get_dns_name(tvbuff_t *tvb, int offset, int dns_data_offset,
209     char *name, int maxname)
210 {
211   int start_offset = offset;
212   char *np = name;
213   int len = -1;
214   int chars_processed = 0;
215   int data_size = tvb_reported_length_remaining(tvb, dns_data_offset);
216   int component_len;
217   int indir_offset;
218
219   const int min_len = 1;        /* Minimum length of encoded name (for root) */
220         /* If we're about to return a value (probably negative) which is less
221          * than the minimum length, we're looking at bad data and we're liable
222          * to put the dissector into a loop.  Instead we throw an exception */
223
224   maxname--;    /* reserve space for the trailing '\0' */
225   for (;;) {
226     component_len = tvb_get_guint8(tvb, offset);
227     offset++;
228     if (component_len == 0)
229       break;
230     chars_processed++;
231     switch (component_len & 0xc0) {
232
233     case 0x00:
234       /* Label */
235       if (np != name) {
236         /* Not the first component - put in a '.'. */
237         if (maxname > 0) {
238           *np++ = '.';
239           maxname--;
240         }
241       }
242       while (component_len > 0) {
243         if (maxname > 0) {
244           *np++ = tvb_get_guint8(tvb, offset);
245           maxname--;
246         }
247         component_len--;
248         offset++;
249         chars_processed++;
250       }
251       break;
252
253     case 0x40:
254       /* Extended label (RFC 2673) */
255       switch (component_len & 0x3f) {
256
257       case 0x01:
258         /* Bitstring label */
259         {
260           int bit_count;
261           int label_len;
262           int print_len;
263
264
265           bit_count = tvb_get_guint8(tvb, offset);
266           offset++;
267           label_len = (bit_count - 1) / 8 + 1;
268
269
270           if (maxname > 0) {
271             print_len = g_snprintf(np, maxname + 1, "\\[x");
272             if (print_len != -1 && print_len < maxname + 1) {
273               /* Some versions of g_snprintf return -1 if they'd truncate
274                  the output. */
275               np += print_len;
276               maxname -= print_len;
277             } else {
278               /* Nothing printed, as there's no room.
279                  Suppress all subsequent printing. */
280               maxname = 0;
281             }
282           }
283           while(label_len--) {
284             if (maxname > 0) {
285               print_len = g_snprintf(np, maxname + 1, "%02x",
286                 tvb_get_guint8(tvb, offset));
287               if (print_len != -1 && print_len < maxname + 1) {
288                 /* Some versions of g_snprintf return -1 if they'd truncate
289                  the output. */
290                 np += print_len;
291                 maxname -= print_len;
292               } else {
293                 /* Nothing printed, as there's no room.
294                    Suppress all subsequent printing. */
295                 maxname = 0;
296               }
297             }
298             offset++;
299           }
300           if (maxname > 0) {
301             print_len = g_snprintf(np, maxname + 1, "/%d]", bit_count);
302             if (print_len != -1 && print_len < maxname + 1) {
303               /* Some versions of g_snprintf return -1 if they'd truncate
304                  the output. */
305               np += print_len;
306               maxname -= print_len;
307             } else {
308               /* Nothing printed, as there's no room.
309                  Suppress all subsequent printing. */
310               maxname = 0;
311             }
312           }
313         }
314         break;
315
316       default:
317         g_strlcpy(name, "<Unknown extended label>", maxname);
318         /* Parsing will propably fail from here on, since the */
319         /* label length is unknown... */
320         len = offset - start_offset;
321         if (len < min_len)
322           THROW(ReportedBoundsError);
323         return len;
324       }
325       break;
326
327     case 0x80:
328       THROW(ReportedBoundsError);
329
330     case 0xc0:
331       /* Pointer. */
332       indir_offset = dns_data_offset +
333           (((component_len & ~0xc0) << 8) | tvb_get_guint8(tvb, offset));
334       offset++;
335       chars_processed++;
336
337       /* If "len" is negative, we are still working on the original name,
338          not something pointed to by a pointer, and so we should set "len"
339          to the length of the original name. */
340       if (len < 0)
341         len = offset - start_offset;
342
343       /* If we've looked at every character in the message, this pointer
344          will make us look at some character again, which means we're
345          looping. */
346       if (chars_processed >= data_size) {
347         g_strlcpy(name, "<Name contains a pointer that loops>", maxname);
348         if (len < min_len)
349           THROW(ReportedBoundsError);
350         return len;
351       }
352
353       offset = indir_offset;
354       break;    /* now continue processing from there */
355     }
356   }
357
358   *np = '\0';
359   /* If "len" is negative, we haven't seen a pointer, and thus haven't
360      set the length, so set it. */
361   if (len < 0)
362     len = offset - start_offset;
363   /* Zero-length name means "root server" */
364   if (*name == '\0')
365     g_strlcpy(name, "<Root>", maxname);
366   if (len < min_len)
367     THROW(ReportedBoundsError);
368   return len;
369 }
370
371
372 static void dissect_getnamebyaddr_request(tvbuff_t* tvb, proto_tree* lwres_tree)
373 {
374         guint32 flags,family;
375         guint16 addrlen, slen;
376         const guint8* addr;
377
378         proto_item* nba_request_item;
379         proto_tree* nba_request_tree;
380
381         flags = tvb_get_ntohl(tvb, LWRES_LWPACKET_LENGTH);
382         family = tvb_get_ntohl(tvb, LWRES_LWPACKET_LENGTH + 4);
383         addrlen = tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH + 8);
384         addr = tvb_get_ptr(tvb, LWRES_LWPACKET_LENGTH + 10, 4);
385         slen = (int)strlen(ip_to_str(addr));
386
387         if(lwres_tree)
388         {
389                 nba_request_item = proto_tree_add_text(lwres_tree,tvb,LWRES_LWPACKET_LENGTH,LWRES_LWPACKET_LENGTH+14,"getnamebyaddr parameters");
390                 nba_request_tree = proto_item_add_subtree(nba_request_item, ett_nba_request);
391         }
392         else return;
393
394                 proto_tree_add_uint(nba_request_tree,
395                                                                 hf_adn_flags,
396                                                                 tvb,
397                                                                 LWRES_LWPACKET_LENGTH,
398                                                                 4,
399                                                                 flags);
400
401                 proto_tree_add_uint(nba_request_tree,
402                                                                 hf_adn_family,
403                                                                 tvb,
404                                                                 LWRES_LWPACKET_LENGTH + 4,
405                                                                 4,
406                                                                 family);
407
408                 proto_tree_add_uint(nba_request_tree,
409                                                                 hf_adn_addr_len,
410                                                                 tvb,
411                                                                 LWRES_LWPACKET_LENGTH + 8,
412                                                                 2,
413                                                                 addrlen);
414
415                 proto_tree_add_string(nba_request_tree,
416                                                                 hf_adn_addr_addr,
417                                                                 tvb,
418                                                                 LWRES_LWPACKET_LENGTH + 10,
419                                                                 slen,
420                                                                 ip_to_str(addr));
421
422 }
423
424 static void dissect_getnamebyaddr_response(tvbuff_t* tvb, proto_tree* lwres_tree)
425 {
426         guint32 flags,i, offset;
427         guint16 naliases,realnamelen,aliaslen;
428         char aliasname[120];
429         char realname[120];
430         
431
432         proto_item* nba_resp_item;
433         proto_tree* nba_resp_tree;
434
435         proto_item* alias_item;
436         proto_tree* alias_tree;
437
438         if(lwres_tree)
439         {
440                 nba_resp_item = proto_tree_add_text(lwres_tree, tvb, LWRES_LWPACKET_LENGTH, 10,"getnamebyaddr records");
441                 nba_resp_tree = proto_item_add_subtree(nba_resp_item, ett_nba_resp);
442         }
443         else return;
444
445         flags = tvb_get_ntohl(tvb, LWRES_LWPACKET_LENGTH);
446         naliases = tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH + 4);
447         realnamelen = tvb_get_ntohs(tvb,LWRES_LWPACKET_LENGTH + 4 + 2);
448         tvb_get_nstringz(tvb, LWRES_LWPACKET_LENGTH + 4 + 2 + 2, realnamelen, (guint8*)realname);
449         realname[realnamelen]='\0';
450
451         proto_tree_add_uint(nba_resp_tree,
452                                                 hf_adn_flags,
453                                                 tvb,
454                                                 LWRES_LWPACKET_LENGTH,
455                                                 4,
456                                                 flags);
457         proto_tree_add_uint(nba_resp_tree,
458                                                 hf_adn_naliases,
459                                                 tvb,
460                                                 LWRES_LWPACKET_LENGTH + 4,
461                                                 2,
462                                                 naliases);
463
464         proto_tree_add_uint(nba_resp_tree,
465                                                 hf_adn_namelen,
466                                                 tvb,
467                                                 LWRES_LWPACKET_LENGTH + 6,
468                                                 2, 
469                                                 realnamelen);
470
471         proto_tree_add_string(nba_resp_tree,
472                                                   hf_adn_realname,
473                                                   tvb,
474                                                   LWRES_LWPACKET_LENGTH + 8,
475                                                   realnamelen,
476                                                   realname);
477
478         offset=LWRES_LWPACKET_LENGTH + 8 + realnamelen;
479
480         if(naliases)
481         {
482                 for(i=0; i<naliases; i++)
483                 {
484                         aliaslen = tvb_get_ntohs(tvb, offset);
485                         tvb_get_nstringz(tvb, offset + 2, aliaslen, (guint8*)aliasname);
486                         aliasname[aliaslen]='\0';
487
488                         alias_item = proto_tree_add_text(nba_resp_tree, tvb, offset, 2 + aliaslen, "Alias %s",aliasname);
489                         alias_tree = proto_item_add_subtree(alias_item, ett_adn_alias);
490
491                         proto_tree_add_uint(alias_tree,
492                                                                 hf_adn_namelen,
493                                                                 tvb,
494                                                                 offset,
495                                                                 2,
496                                                                 aliaslen);
497
498                         proto_tree_add_string(alias_tree,
499                                                                 hf_adn_aliasname,
500                                                                 tvb,
501                                                                 offset + 2,
502                                                                 aliaslen,
503                                                                 aliasname);
504
505                         offset+=(2 + aliaslen + 1);
506                 }
507         }
508 }
509
510 static void dissect_getaddrsbyname_request(tvbuff_t* tvb, proto_tree* lwres_tree)
511 {
512         guint32 flags,addrtype;
513         guint16 namelen;
514         guint8  name[120];
515
516         proto_item* adn_request_item;
517         proto_tree* adn_request_tree;
518         
519         flags = tvb_get_ntohl(tvb, LWRES_LWPACKET_LENGTH);
520         addrtype = tvb_get_ntohl(tvb, LWRES_LWPACKET_LENGTH + 4);
521         namelen  = tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH + 8);
522         tvb_get_nstringz(tvb, LWRES_LWPACKET_LENGTH+10, namelen, name);
523         name[namelen]='\0';
524
525         if(lwres_tree)
526         {
527                 adn_request_item = proto_tree_add_text(lwres_tree,tvb,
528                                                 LWRES_LWPACKET_LENGTH,10+namelen+1,
529                                                 "getaddrbyname parameters");
530                 adn_request_tree = proto_item_add_subtree(adn_request_item, ett_adn_request);
531         }
532         else
533                 return;
534
535
536         proto_tree_add_uint(adn_request_tree,
537                                 hf_adn_flags,
538                                 tvb,
539                                 LWRES_LWPACKET_LENGTH+0,
540                                 sizeof(guint32),
541                                 flags);
542
543         proto_tree_add_uint(adn_request_tree,
544                                 hf_adn_addrtype,
545                                 tvb,
546                                 LWRES_LWPACKET_LENGTH+4,
547                                 sizeof(guint32),
548                                 addrtype);
549
550         proto_tree_add_uint(adn_request_tree,
551                                 hf_adn_namelen,
552                                 tvb,
553                                 LWRES_LWPACKET_LENGTH+8,
554                                 sizeof(guint16),
555                                 namelen);
556
557         proto_tree_add_string(adn_request_tree,
558                                 hf_adn_name,
559                                 tvb,
560                                 LWRES_LWPACKET_LENGTH+10,
561                                 namelen,
562                                 (gchar*)name);
563         
564 }
565
566
567 static void dissect_getaddrsbyname_response(tvbuff_t* tvb, proto_tree* lwres_tree)
568 {
569         guint32 flags, family ,i, offset;
570         guint16 naliases, naddrs, realnamelen, length, aliaslen;
571         const gchar* addr;
572         guint slen;
573         char realname[120];
574         char aliasname[120];
575
576         proto_item* adn_resp_item;
577         proto_tree* adn_resp_tree;
578         proto_item* alias_item;
579         proto_tree* alias_tree;
580         proto_item* addr_item;
581         proto_tree* addr_tree;
582
583         
584
585         if(lwres_tree)
586         {
587                 adn_resp_item = proto_tree_add_text(lwres_tree, tvb, LWRES_LWPACKET_LENGTH, 10, "getaddrbyname records");
588                 adn_resp_tree = proto_item_add_subtree(adn_resp_item, ett_adn_resp);
589         }
590         else return;
591
592         flags = tvb_get_ntohl(tvb, LWRES_LWPACKET_LENGTH);
593         naliases = tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH + 4);
594         naddrs   = tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH + 6);
595         realnamelen = tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH + 8);
596         tvb_get_nstringz(tvb, LWRES_LWPACKET_LENGTH + 10, realnamelen, (guint8*)realname);
597         realname[realnamelen]='\0';
598
599         
600         proto_tree_add_uint(adn_resp_tree,
601                                                 hf_adn_flags,
602                                                 tvb, 
603                                                 LWRES_LWPACKET_LENGTH,
604                                                 4,
605                                                 flags);
606
607         proto_tree_add_uint(adn_resp_tree,
608                                                 hf_adn_naliases,
609                                                 tvb, 
610                                                 LWRES_LWPACKET_LENGTH + 4,
611                                                 2,
612                                                 naliases);
613
614         proto_tree_add_uint(adn_resp_tree,
615                                                 hf_adn_naddrs,
616                                                 tvb,
617                                                 LWRES_LWPACKET_LENGTH + 6,
618                                                 2,
619                                                 naddrs);
620
621         proto_tree_add_uint(adn_resp_tree,
622                                                 hf_adn_namelen,
623                                                 tvb,
624                                                 LWRES_LWPACKET_LENGTH + 8,
625                                                 2, 
626                                                 realnamelen);
627         
628         proto_tree_add_string(adn_resp_tree,
629                                                 hf_adn_realname,
630                                                 tvb,
631                                                 LWRES_LWPACKET_LENGTH + 10,
632                                                 realnamelen,
633                                                 realname);
634
635         offset = LWRES_LWPACKET_LENGTH + 10 + realnamelen + 1;
636
637         if(naliases)
638         {
639                 for(i=0; i<naliases; i++)
640                 {
641                         aliaslen = tvb_get_ntohs(tvb, offset);
642                         tvb_get_nstringz(tvb, offset + 2, aliaslen, (guint8*)aliasname);
643                         aliasname[aliaslen]='\0';
644
645                         alias_item = proto_tree_add_text(adn_resp_tree, tvb, offset, 2 + aliaslen, "Alias %s",aliasname);
646                         alias_tree = proto_item_add_subtree(alias_item, ett_adn_alias);
647
648                         proto_tree_add_uint(alias_tree,
649                                                                 hf_adn_namelen,
650                                                                 tvb,
651                                                                 offset,
652                                                                 2,
653                                                                 aliaslen);
654
655                         proto_tree_add_string(alias_tree,
656                                                                 hf_adn_aliasname,
657                                                                 tvb,
658                                                                 offset + 2,
659                                                                 aliaslen,
660                                                                 aliasname);
661
662                         offset+=(2 + aliaslen + 1);
663                 }
664         }
665
666         if(naddrs)
667         {
668                 for(i=0; i < naddrs; i++)
669                 {
670                         family = tvb_get_ntohl(tvb, offset);
671                         length = tvb_get_ntohs(tvb, offset + 4);
672                         addr = (gchar*)tvb_get_ptr(tvb, offset + 6, 4);
673                         slen = (int)strlen((char*)ip_to_str((guint8*)addr));
674                 
675                         addr_item = proto_tree_add_text(adn_resp_tree,tvb, offset, 4+2+4, "Address %s",ip_to_str((guint8*)addr));
676                         addr_tree = proto_item_add_subtree(addr_item, ett_adn_addr);
677
678                         proto_tree_add_uint(addr_tree, 
679                                                                 hf_adn_family,
680                                                                 tvb, 
681                                                                 offset, 
682                                                                 4,
683                                                                 family);
684
685                         proto_tree_add_uint(addr_tree,
686                                                                 hf_adn_addr_len,
687                                                                 tvb,
688                                                                 offset + 4,
689                                                                 2,
690                                                                 length);
691
692                         proto_tree_add_string(addr_tree,
693                                                                 hf_adn_addr_addr,
694                                                                 tvb,
695                                                                 offset + 6,
696                                                                 slen,
697                                                                 ip_to_str((guint8*)addr));
698
699                         offset+= 4 + 2 + 4;
700                 }
701         }
702
703
704 }
705
706 static void dissect_a_records(tvbuff_t* tvb, proto_tree* tree,guint32 nrec,int offset)
707 {
708         guint32 i, curr;
709         const gchar* addr;
710         guint16 len;
711         proto_item* a_rec_item;
712         proto_tree* a_rec_tree;
713         proto_item* addr_item;
714         proto_tree* addr_tree;
715
716         if(tree)
717         {
718                 a_rec_item = proto_tree_add_text(tree,tvb,offset,
719                                         ((sizeof(guint32) + sizeof(guint16)) * nrec),"A records");
720
721                 a_rec_tree = proto_item_add_subtree(a_rec_item, ett_a_rec);
722         }
723         else 
724                 return;
725
726         for(i=0; i<nrec; i++)
727         {
728         
729                 curr = offset + ((sizeof(guint32)+sizeof(guint16)) * i);
730
731                 len  = tvb_get_ntohs(tvb,curr);
732                 addr = (gchar*)tvb_get_ptr(tvb,curr+2,4);
733
734                 if(a_rec_tree)
735                 {
736                         addr_item = proto_tree_add_text(a_rec_tree,tvb, curr, 6,"IP Address");
737                         addr_tree = proto_item_add_subtree(addr_item, ett_a_rec_addr);
738                         proto_item_set_text(addr_item,"Address %s",ip_to_str((guint8*)addr));
739                 }
740                 else return;
741                 
742                 proto_tree_add_uint(addr_tree,
743                                         hf_a_rec_len,
744                                         tvb,
745                                         curr,
746                                         sizeof(guint16),
747                                         len);
748
749                 proto_tree_add_text(addr_tree, 
750                                                 tvb,
751                                                 curr + 2, 
752                                                 4, 
753                                                 "Addr: %s",
754                                                 ip_to_str((guint8*)addr));
755                 
756         }
757
758 }
759
760 static void dissect_srv_records(tvbuff_t* tvb, proto_tree* tree,guint32 nrec,int offset)
761 {
762         guint32 i, curr;
763         guint16 len, priority, weight, port, namelen, dlen;
764         const char *cmpname;
765         guint8 dname[120];
766
767         proto_item* srv_rec_item, *rec_item;
768         proto_item* srv_rec_tree, *rec_tree;
769
770         if(tree)
771         {
772                 srv_rec_item = proto_tree_add_text(tree, tvb, offset, offset, "SRV records");
773                 srv_rec_tree = proto_item_add_subtree(srv_rec_item, ett_srv_rec);
774                                proto_item_set_text(srv_rec_item, "SRV records (%d)", nrec);
775         }
776         else return;
777
778         curr = offset;
779
780         for(i=0; i < nrec; i++)
781         {
782                 len =      tvb_get_ntohs(tvb, curr);
783                 priority = tvb_get_ntohs(tvb, curr + 2);
784                 weight   = tvb_get_ntohs(tvb, curr + 4);
785                 port     = tvb_get_ntohs(tvb, curr + 6);
786                 namelen = len - 8;
787                 cmpname  = (char*)tvb_get_ptr(tvb, curr + 8, namelen);
788
789                 dlen = lwres_get_dns_name(tvb, curr + 8, curr, (gchar*)dname, sizeof(dname));
790
791                 if(srv_rec_tree)
792                 {
793                         rec_item = proto_tree_add_text(srv_rec_tree, tvb, curr, 6,"  ");
794                         rec_tree = proto_item_add_subtree(rec_item, ett_srv_rec_item);
795                         proto_item_set_text(rec_item,
796                                                 "SRV record:pri=%d,w=%d,port=%d,dname=%s",
797                                                 priority,
798                                                 weight,
799                                                 port,
800                                                 dname); 
801                 }
802                 else return;
803
804                 proto_tree_add_uint(rec_tree,
805                                                 hf_srv_prio,
806                                                 tvb,
807                                                 curr + 2,
808                                                 2,
809                                                 priority);
810
811                 proto_tree_add_uint(rec_tree,
812                                                 hf_srv_weight,
813                                                 tvb,
814                                                 curr + 4,
815                                                 2,
816                                                 weight);
817
818                 proto_tree_add_uint(rec_tree,
819                                                 hf_srv_port,
820                                                 tvb,
821                                                 curr + 6,
822                                                 2,
823                                                 port);
824
825
826                 proto_tree_add_text(rec_tree,
827                                                         tvb,
828                                                         curr + 8,
829                                                         dlen,
830                                                         "DNAME: %s", dname);
831
832                 curr+=((sizeof(short)*4) + dlen);
833                                                         
834         }
835
836 }
837
838 static void dissect_mx_records(tvbuff_t* tvb, proto_tree* tree, guint32 nrec, int offset)
839 {
840         
841         guint32 i, curr;
842         guint16 len, priority, dlen, namelen;
843         const char* cname;
844         guint8 dname[120];
845
846         proto_item* mx_rec_item, *rec_item;
847         proto_tree* mx_rec_tree, *rec_tree;
848         
849
850         if(tree)
851         {
852                 mx_rec_item = proto_tree_add_text(tree, tvb, offset, offset, "MX records (%d)", nrec);
853                 mx_rec_tree = proto_item_add_subtree(mx_rec_item, ett_mx_rec);
854         }
855         else
856                 return;
857         
858         curr = offset;
859         for(i=0; i < nrec; i++)
860         {
861                 len =           tvb_get_ntohs(tvb, curr);
862                 priority =  tvb_get_ntohs(tvb, curr + 2);
863                 namelen  =  len - 4;
864                 cname = (char*)tvb_get_ptr(tvb, curr + 4, 4);
865                 dlen  = lwres_get_dns_name(tvb, curr + 4, curr, (gchar*)dname, sizeof(dname));
866                 if(mx_rec_tree)
867                 {
868                         rec_item = proto_tree_add_text(mx_rec_tree, tvb, curr,6,"MX record: pri=%d,dname=%s",
869                                                 priority,dname);
870                         rec_tree = proto_item_add_subtree(rec_item, ett_mx_rec_item);
871                 }
872                 else 
873                         return;
874
875                 
876                 proto_tree_add_uint(rec_tree,
877                                                         hf_srv_prio,
878                                                         tvb,
879                                                         curr + 2,
880                                                         2,
881                                                         priority);
882         
883                 proto_tree_add_text(rec_tree,
884                                                         tvb,
885                                                         curr + 4,
886                                                         dlen,
887                                                         "name: %s", dname);
888
889                 curr+=((sizeof(short)*2) + dlen);
890         
891
892         }
893         
894 }
895
896 static void dissect_ns_records(tvbuff_t* tvb, proto_tree* tree, guint32 nrec, int offset)
897 {
898         guint32 i, curr;
899         guint16 len, dlen, namelen;
900         guint8 dname[120];
901
902         proto_item* ns_rec_item, *rec_item;
903         proto_tree* ns_rec_tree, *rec_tree;
904         
905         if(tree)
906         {
907                 ns_rec_item = proto_tree_add_text(tree, tvb, offset, offset, "NS record (%d)", nrec);
908                 ns_rec_tree = proto_item_add_subtree(ns_rec_item, ett_ns_rec);
909         }
910         else
911                 return;
912         curr=offset;
913
914         for(i=0;i<nrec;i++)
915         {
916                 len = tvb_get_ntohs(tvb, curr);
917                 namelen = len - 2;
918                 dlen = lwres_get_dns_name(tvb, curr + 2, curr, (char*)dname, sizeof(dname));
919                 if(ns_rec_tree)
920                 {
921                         rec_item = proto_tree_add_text(ns_rec_tree, tvb, curr,4, "NS record: dname=%s",dname);
922                         rec_tree = proto_item_add_subtree(rec_item, ett_ns_rec_item);
923                 }
924                 else
925                         return;
926
927                 proto_tree_add_text(rec_tree,
928                                                         tvb,
929                                                         curr + 2,
930                                                         dlen,
931                                                         "Name: %s", dname);
932                 curr+=(sizeof(short) + dlen);
933                                                         
934         }
935         
936
937 }
938
939 static void dissect_rdata_request(tvbuff_t* tvb, proto_tree* lwres_tree)
940 {
941         guint32 rflags;
942         guint16 rdclass, rdtype, namelen;
943         guint8 name[120];
944
945         proto_item* rdata_request_item;
946         proto_tree* rdata_request_tree;
947
948         rflags = tvb_get_ntohl(tvb, LWRES_LWPACKET_LENGTH+0);
949         rdclass = tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH+4);
950         rdtype =  tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH+6);
951         namelen = tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH+8);
952         tvb_get_nstringz(tvb, LWRES_LWPACKET_LENGTH+10, namelen, name);
953         name[namelen]='\0';
954
955         if(lwres_tree)
956         {
957                 rdata_request_item = 
958                         proto_tree_add_text(lwres_tree,tvb,LWRES_LWPACKET_LENGTH,10+namelen+1,"RDATA request parameters");
959                 rdata_request_tree = proto_item_add_subtree(rdata_request_item, ett_rdata_req);
960         }
961         else 
962                 return;
963
964         proto_tree_add_uint(rdata_request_tree,
965                         hf_rflags,
966                         tvb,
967                         LWRES_LWPACKET_LENGTH+0,
968                         sizeof(guint32),
969                         rflags);
970
971         proto_tree_add_uint(rdata_request_tree,
972                         hf_rdclass,
973                         tvb,
974                         LWRES_LWPACKET_LENGTH+4,
975                         sizeof(guint16),
976                         rdclass);
977
978         proto_tree_add_uint(rdata_request_tree,
979                         hf_rdtype,
980                         tvb,
981                         LWRES_LWPACKET_LENGTH+6,
982                         sizeof(guint16),
983                         rdtype);
984
985         proto_tree_add_uint(rdata_request_tree,
986                         hf_namelen,
987                         tvb,
988                         LWRES_LWPACKET_LENGTH+8,
989                         sizeof(guint16),
990                         namelen);
991
992         proto_tree_add_string(rdata_request_tree,
993                         hf_req_name,
994                         tvb,
995                         LWRES_LWPACKET_LENGTH+10,
996                         namelen,
997                         (char*)name);
998
999 }
1000
1001 static void dissect_rdata_response(tvbuff_t* tvb, proto_tree* lwres_tree)
1002 {
1003         guint32 rflags, ttl, offset;
1004         guint16 rdclass, rdtype, nrdatas, nsigs, realnamelen;
1005         guint8 realname[120];
1006
1007         proto_item* rdata_resp_item;
1008         proto_tree* rdata_resp_tree;
1009
1010         rflags = tvb_get_ntohl(tvb, LWRES_LWPACKET_LENGTH+0);
1011         rdclass = tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH+4);
1012         rdtype =  tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH+6);
1013         ttl    =  tvb_get_ntohl(tvb, LWRES_LWPACKET_LENGTH+8);
1014         nrdatas = tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH+12);
1015         nsigs   = tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH+14);
1016         realnamelen = tvb_get_ntohs(tvb,LWRES_LWPACKET_LENGTH+16);
1017         tvb_get_nstringz(tvb,LWRES_LWPACKET_LENGTH+18,realnamelen, realname);
1018         realname[realnamelen]='\0';
1019
1020         offset = LWRES_LWPACKET_LENGTH + 18 + realnamelen + 1;
1021
1022         if(lwres_tree)
1023         {
1024                 rdata_resp_item = proto_tree_add_text(lwres_tree,tvb,LWRES_LWPACKET_LENGTH, 18+realnamelen+1,"RDATA response");
1025                 rdata_resp_tree = proto_item_add_subtree(rdata_resp_item, ett_rdata_resp);
1026         }
1027         else
1028                 return;
1029
1030         proto_tree_add_uint(rdata_resp_tree,
1031                         hf_rflags,
1032                         tvb,
1033                         LWRES_LWPACKET_LENGTH+0,
1034                         sizeof(guint32),
1035                         rflags);
1036
1037         proto_tree_add_uint(rdata_resp_tree,
1038                         hf_rdclass,
1039                         tvb,
1040                         LWRES_LWPACKET_LENGTH+4,
1041                         sizeof(guint16),
1042                         rdclass);
1043
1044         proto_tree_add_uint(rdata_resp_tree,
1045                         hf_rdtype,
1046                         tvb,
1047                         LWRES_LWPACKET_LENGTH+6,
1048                         sizeof(guint16),
1049                         rdtype);
1050
1051         proto_tree_add_uint(rdata_resp_tree,
1052                         hf_ttl,
1053                         tvb,
1054                         LWRES_LWPACKET_LENGTH+8,
1055                         sizeof(guint32),
1056                         ttl);
1057
1058         proto_tree_add_uint(rdata_resp_tree,
1059                         hf_nrdatas,
1060                         tvb,
1061                         LWRES_LWPACKET_LENGTH+12,
1062                         sizeof(guint16),
1063                         nrdatas);
1064
1065         proto_tree_add_uint(rdata_resp_tree,
1066                         hf_nsigs,
1067                         tvb,
1068                         LWRES_LWPACKET_LENGTH+14,
1069                         sizeof(guint16),
1070                         nsigs);
1071
1072         proto_tree_add_uint(rdata_resp_tree,
1073                         hf_realnamelen,
1074                         tvb,
1075                         LWRES_LWPACKET_LENGTH+16,
1076                         sizeof(guint16),
1077                         realnamelen);
1078
1079         proto_tree_add_string(rdata_resp_tree,
1080                         hf_realname,
1081                         tvb,
1082                         LWRES_LWPACKET_LENGTH+18,
1083                         realnamelen,
1084                         (char*)realname);
1085
1086         switch(rdtype)
1087         {
1088                 case T_A:
1089                         dissect_a_records(tvb,rdata_resp_tree,nrdatas,offset);
1090                 break;
1091
1092                 case T_SRV:
1093                         dissect_srv_records(tvb,rdata_resp_tree,nrdatas, offset);
1094                 break;
1095
1096                 case T_MX:
1097                         dissect_mx_records(tvb,rdata_resp_tree,nrdatas, offset);
1098                 break;
1099
1100                 case T_NS:
1101                         dissect_ns_records(tvb,rdata_resp_tree,nrdatas, offset);
1102                 break;
1103         }
1104
1105 }
1106
1107 static void dissect_noop(tvbuff_t* tvb, proto_tree* lwres_tree)
1108 {
1109         guint16 datalen;
1110         const char* data;
1111
1112         proto_item* noop_item;
1113         proto_tree* noop_tree;
1114
1115         datalen = tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH);
1116         data = (char*)tvb_get_ptr(tvb, LWRES_LWPACKET_LENGTH, datalen);
1117         
1118         if(lwres_tree)
1119         {
1120                 noop_item = proto_tree_add_text(lwres_tree, tvb, LWRES_LWPACKET_LENGTH, 10, "Noop record");
1121                 noop_tree = proto_item_add_subtree(noop_item, ett_noop);
1122         }
1123         else
1124                 return;
1125
1126         proto_tree_add_uint(noop_tree,
1127                                                 hf_length,
1128                                                 tvb,
1129                                                 LWRES_LWPACKET_LENGTH,
1130                                                 sizeof(guint16),
1131                                                 datalen);
1132
1133 }
1134
1135 static void dissect_getaddrsbyname(tvbuff_t* tvb, proto_tree* lwres_tree, int type)
1136 {
1137         if(type == 1)
1138                 dissect_getaddrsbyname_request(tvb, lwres_tree);
1139         else
1140                 dissect_getaddrsbyname_response(tvb, lwres_tree);
1141 }
1142
1143 static void dissect_getnamebyaddr(tvbuff_t* tvb, proto_tree* lwres_tree, int type)
1144 {
1145         if(type == 1)
1146                 dissect_getnamebyaddr_request(tvb, lwres_tree);
1147         else
1148                 dissect_getnamebyaddr_response(tvb, lwres_tree);
1149 }
1150
1151 static void dissect_getrdatabyname(tvbuff_t* tvb, proto_tree* lwres_tree, int type)
1152 {
1153         if(type == 1) 
1154                 dissect_rdata_request(tvb, lwres_tree);
1155         else            
1156                 dissect_rdata_response(tvb, lwres_tree);
1157 }
1158
1159 static void
1160 dissect_lwres(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1161 {
1162         guint16 version, flags, authtype, authlength ;
1163         guint32 length, opcode, result, recvlength, serial;
1164         guint32 message_type;
1165
1166         proto_item* lwres_item;
1167         proto_tree* lwres_tree;
1168
1169         col_set_str(pinfo->cinfo, COL_PROTOCOL, "lw_res");
1170         length = tvb_get_ntohl(tvb, LW_LENGTH_OFFSET);
1171         version = tvb_get_ntohs(tvb, LW_VERSION_OFFSET);
1172         flags = tvb_get_ntohs(tvb, LW_PKTFLASG_OFFSET);
1173         serial = tvb_get_ntohl(tvb, LW_SERIAL_OFFSET);
1174         opcode = tvb_get_ntohl(tvb,LW_OPCODE_OFFSET);
1175         result = tvb_get_ntohl(tvb, LW_RESULT_OFFSET);
1176         recvlength = tvb_get_ntohl(tvb, LW_RECVLEN_OFFSET);
1177         authtype = tvb_get_ntohs(tvb, LW_AUTHTYPE_OFFSET);
1178         authlength = tvb_get_ntohs(tvb, LW_AUTHLEN_OFFSET);
1179
1180         message_type = (flags & LWRES_LWPACKETFLAG_RESPONSE) ? 2 : 1;
1181
1182         if (check_col(pinfo->cinfo, COL_INFO)) {
1183                 col_clear(pinfo->cinfo, COL_INFO);
1184
1185                 if(flags & LWRES_LWPACKETFLAG_RESPONSE)
1186                 {
1187                         col_add_fstr(pinfo->cinfo, COL_INFO,
1188                         "%s, opcode=%s, serial=0x%x, result=%s",
1189                                 val_to_str((guint32)message_type,message_types_values,"unknown"),
1190                                 val_to_str(opcode, opcode_values, "unknown"),
1191                                                 serial,
1192                                                 val_to_str(result,result_values,"unknown"));
1193                 }
1194                 else
1195                 {
1196                         col_add_fstr(pinfo->cinfo, COL_INFO,
1197                                 "%s, opcode=%s, serial=0x%x",
1198                                 val_to_str((guint32)message_type,message_types_values,"unknown"),
1199                                                 val_to_str(opcode, opcode_values, "unknown"),
1200                                 serial);
1201                 }
1202         }
1203
1204         if(tree)
1205         {
1206                 lwres_item = proto_tree_add_item(tree,proto_lwres, tvb,0, -1, FALSE);
1207                 lwres_tree = proto_item_add_subtree(lwres_item, ett_lwres);
1208         }
1209         else return;
1210
1211
1212         proto_tree_add_uint(lwres_tree,
1213                         hf_length,
1214                         tvb,
1215                         LW_LENGTH_OFFSET,
1216                         sizeof(guint32),
1217                         length);
1218
1219
1220         proto_tree_add_uint(lwres_tree,
1221                                 hf_version,
1222                                 tvb,
1223                                 LW_VERSION_OFFSET,
1224                                 sizeof(guint16),
1225                                 version);
1226                 
1227
1228
1229
1230         proto_tree_add_uint(lwres_tree,
1231                                 hf_flags,
1232                                 tvb,
1233                                 LW_PKTFLASG_OFFSET,
1234                                 sizeof(guint16),
1235                                 flags);
1236
1237         proto_tree_add_uint(lwres_tree,
1238                                 hf_serial,
1239                                 tvb,
1240                                 LW_SERIAL_OFFSET,
1241                                 sizeof(guint32),
1242                                 serial);
1243
1244         proto_tree_add_uint(lwres_tree,
1245                                 hf_opcode,
1246                                 tvb,
1247                                 LW_OPCODE_OFFSET,
1248                                 sizeof(guint32),
1249                                 opcode);
1250
1251         proto_tree_add_uint(lwres_tree,
1252                                 hf_result,
1253                                 tvb,
1254                                 LW_RESULT_OFFSET,
1255                                 sizeof(guint32),
1256                                 result);
1257
1258         proto_tree_add_uint(lwres_tree,
1259                                 hf_recvlen,
1260                                 tvb,
1261                                 LW_RECVLEN_OFFSET,
1262                                 sizeof(guint32),
1263                                 recvlength);
1264
1265         proto_tree_add_uint(lwres_tree,
1266                                 hf_authtype,
1267                                 tvb,
1268                                 LW_AUTHTYPE_OFFSET,
1269                                 sizeof(guint16),
1270                                 authtype);
1271
1272         proto_tree_add_uint(lwres_tree,
1273                                 hf_authlen,
1274                                 tvb,
1275                                 LW_AUTHLEN_OFFSET,
1276                                 sizeof(guint16),
1277                                 authlength);
1278
1279         if(!result)
1280         {
1281                 switch(opcode)
1282                 {
1283                         case LWRES_OPCODE_NOOP:
1284                                 dissect_noop(tvb, lwres_tree);
1285                         break;
1286
1287                         case LWRES_OPCODE_GETADDRSBYNAME:
1288                                 dissect_getaddrsbyname(tvb, lwres_tree, message_type);
1289                         break;
1290
1291                         case LWRES_OPCODE_GETNAMEBYADDR:
1292                                 dissect_getnamebyaddr(tvb, lwres_tree, message_type);
1293                         break;
1294
1295                         case LWRES_OPCODE_GETRDATABYNAME:
1296                                 dissect_getrdatabyname(tvb, lwres_tree, message_type);
1297                         break;
1298                 }
1299         }
1300
1301 }
1302
1303
1304 void
1305 proto_register_lwres(void)
1306 {
1307   static hf_register_info hf[] = {
1308     { &hf_length,
1309       { "Length", "lwres.length", FT_UINT32, BASE_DEC, NULL, 0x0,
1310         "lwres length", HFILL }},
1311
1312     { &hf_version,
1313       { "Version", "lwres.version", FT_UINT16, BASE_DEC, NULL, 0x0,
1314         "lwres version", HFILL }},
1315
1316     { &hf_flags,
1317       { "Packet Flags", "lwres.flags", FT_UINT16, BASE_HEX, NULL, 0x0,
1318         "lwres flags", HFILL }},
1319
1320     { &hf_serial,
1321       { "Serial", "lwres.serial", FT_UINT32, BASE_HEX, NULL, 0x0,
1322         "lwres serial", HFILL }},
1323
1324     { &hf_opcode,
1325       { "Operation code", "lwres.opcode", FT_UINT32, BASE_DEC, VALS(opcode_values), 0x0,
1326         "lwres opcode", HFILL }},
1327
1328     { &hf_result,
1329       { "Result", "lwres.result", FT_UINT32, BASE_DEC, VALS(result_values), 0x0,
1330         "lwres result", HFILL }},
1331
1332     { &hf_recvlen, 
1333       { "Received length", "lwres.recvlen", FT_UINT32, BASE_DEC, NULL, 0x0,
1334         "lwres recvlen", HFILL }},
1335
1336     { &hf_authtype,
1337       { "Auth. type", "lwres.authtype", FT_UINT16, BASE_DEC, NULL, 0x0,
1338         "lwres authtype", HFILL }},
1339
1340     { &hf_authlen,
1341       { "Auth. length", "lwres.authlen" , FT_UINT16, BASE_DEC, NULL, 0x0,
1342         "lwres authlen", HFILL }},
1343
1344     { &hf_rflags, 
1345       { "Flags", "lwres.rflags", FT_UINT32, BASE_HEX, NULL, 0x0,
1346         "lwres rflags", HFILL }},
1347     { &hf_rdclass,
1348       { "Class", "lwres.class", FT_UINT16, BASE_DEC, NULL, 0x0,
1349         "lwres class", HFILL }},
1350
1351     { &hf_rdtype,
1352       { "Type", "lwres.type", FT_UINT16, BASE_DEC, VALS(t_types), 0x0,
1353         "lwres type" , HFILL }},
1354
1355     { &hf_namelen,
1356       { "Name length", "lwres.namelen", FT_UINT16, BASE_DEC, NULL, 0x0,
1357         "lwres namelen", HFILL }},
1358
1359     { &hf_req_name,
1360       { "Domain name" , "lwres.reqdname" , FT_STRING, BASE_NONE, NULL, 0x0,
1361         "lwres reqdname", HFILL }},
1362
1363     { &hf_ttl,
1364       { "Time To Live", "lwres.ttl", FT_UINT32, BASE_DEC, NULL, 0x0, 
1365         "lwres ttl", HFILL }},
1366
1367     { &hf_nrdatas,
1368       { "Number of rdata records", "lwres.nrdatas", FT_UINT16, BASE_DEC, NULL, 0x0,
1369         "lwres nrdatas" , HFILL }},
1370    
1371     { &hf_nsigs,
1372       { "Number of signature records", "lwres.nsigs", FT_UINT16, BASE_DEC, NULL, 0x0,
1373         "lwres nsigs" , HFILL }},
1374
1375     { &hf_realnamelen,
1376       { "Real name length", "lwres.realnamelen", FT_UINT16, BASE_DEC, NULL, 0x0,
1377         "lwres realnamelen", HFILL }},
1378
1379     { &hf_realname,
1380       { "Real doname name", "lwres.realname", FT_STRING, BASE_NONE, NULL, 0x0,
1381         "lwres realname", HFILL }},
1382
1383         { &hf_a_record,
1384         { "IPv4 Address", "lwres.arecord", FT_UINT32, BASE_DEC, NULL, 0x0,
1385           "lwres arecord", HFILL }},
1386
1387         { &hf_a_rec_len,
1388         { "Length", "lwres.areclen", FT_UINT16, BASE_DEC, NULL, 0x0,
1389         "lwres areclen", HFILL }},
1390
1391         { &hf_srv_prio,
1392         { "Priority", "lwres.srv.priority", FT_UINT16, BASE_DEC, NULL, 0x0,
1393            "lwres srv prio", HFILL }},
1394
1395         { &hf_srv_weight,
1396         { "Weight", "lwres.srv.weight", FT_UINT16, BASE_DEC, NULL, 0x0,
1397         "lwres srv weight", HFILL }},
1398
1399         { &hf_srv_port,
1400         { "Port" , "lwres.srv.port", FT_UINT16, BASE_DEC, NULL, 0x0,
1401         "lwres srv port", HFILL }},
1402
1403         { &hf_adn_flags,
1404         { "Flags", "lwres.adn.flags", FT_UINT32, BASE_HEX, NULL, 0x0,
1405           "lwres adn flags", HFILL }},
1406
1407         { &hf_adn_addrtype,
1408         { "Address type", "lwres.adn.addrtype", FT_UINT32, BASE_DEC, NULL, 0x0,
1409           "lwres adn addrtype", HFILL }},
1410
1411         { &hf_adn_namelen,
1412         { "Name length", "lwres.adn.namelen", FT_UINT16, BASE_DEC, NULL, 0x0,
1413           "lwres adn namelen", HFILL }},
1414
1415         { &hf_adn_name,
1416         { "Name", "lwres.adn.name", FT_STRING, BASE_NONE, NULL, 0x0,
1417           "lwres adn name", HFILL }}, 
1418
1419          { &hf_adn_naliases,
1420         { "Number of aliases", "lwres.adn.naliases", FT_UINT16, BASE_DEC, NULL, 0x0,
1421           "lwres adn naliases", HFILL }}, 
1422
1423           { &hf_adn_naddrs,
1424         { "Number of addresses", "lwres.adn.naddrs", FT_UINT16, BASE_DEC, NULL, 0x0,
1425           "lwres adn naddrs", HFILL }}, 
1426
1427                 { &hf_adn_realname,
1428         { "Real name", "lwres.adn.realname", FT_STRING, BASE_NONE, NULL, 0x0,
1429           "lwres adn realname", HFILL }}, 
1430
1431                 { &hf_adn_aliasname,
1432         { "Alias name", "lwres.adn.aliasname", FT_STRING, BASE_NONE, NULL, 0x0,
1433           "lwres adn aliasname", HFILL }}, 
1434
1435         { &hf_adn_family,
1436         { "Address family", "lwres.adn.addr.family", FT_UINT32, BASE_DEC, NULL, 0x0,
1437         "lwres adn addr family", HFILL }},
1438
1439         { &hf_adn_addr_len,
1440         { "Address length", "lwres.adn.addr.length", FT_UINT16, BASE_DEC, NULL, 0x0,
1441         "lwres adn addr length", HFILL }},
1442
1443         { &hf_adn_addr_addr,
1444     { "IP Address", "lwres.adn.addr.addr", FT_STRING, BASE_NONE, NULL, 0x0,
1445           "lwres adn addr addr", HFILL }},
1446
1447     /* Add more fields here */
1448   };
1449
1450   static gint *ett[] = {
1451     &ett_lwres,
1452     &ett_rdata_req,
1453     &ett_rdata_resp,
1454         &ett_a_rec,
1455         &ett_a_rec_addr,
1456         &ett_srv_rec,
1457         &ett_srv_rec_item,
1458         &ett_adn_request,
1459         &ett_adn_resp,
1460         &ett_adn_alias,
1461         &ett_adn_addr,
1462         &ett_nba_request,
1463         &ett_nba_resp,
1464         &ett_mx_rec,
1465         &ett_mx_rec_item,
1466         &ett_ns_rec,
1467         &ett_ns_rec_item,
1468         &ett_noop,
1469   };
1470
1471
1472   module_t *lwres_module;
1473
1474   proto_lwres = proto_register_protocol("Light Weight DNS RESolver (BIND9)",
1475                                        "LWRES", "lwres");
1476
1477   proto_register_field_array(proto_lwres, hf, array_length(hf));
1478   proto_register_subtree_array(ett, array_length(ett));
1479
1480   lwres_module = prefs_register_protocol(proto_lwres, proto_reg_handoff_lwres);
1481
1482   prefs_register_uint_preference(lwres_module, "udp.lwres_port",
1483                                  "lwres listener UDP Port",
1484                                  "Set the UDP port for lwres daemon"
1485                                  "(if other than the default of 921)",
1486                                  10, &global_lwres_port);
1487
1488 }
1489
1490 /* The registration hand-off routine */
1491 void
1492 proto_reg_handoff_lwres(void)
1493 {
1494   static gboolean lwres_prefs_initialized = FALSE;
1495   static dissector_handle_t lwres_handle;
1496   static guint lwres_port;
1497
1498   if(!lwres_prefs_initialized) {
1499     lwres_handle = create_dissector_handle(dissect_lwres, proto_lwres);
1500     lwres_prefs_initialized = TRUE;
1501   }
1502   else {
1503     dissector_delete("udp.port", lwres_port, lwres_handle);
1504   }
1505
1506   dissector_add("udp.port", global_lwres_port, lwres_handle);
1507   lwres_port = global_lwres_port;
1508
1509 }