nrelease - fix/improve livecd
[dragonfly.git] / contrib / tcpdump / print-lwres.c
1 /*
2  * Copyright (C) 2001 WIDE Project.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the project nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 /* \summary: BIND9 Lightweight Resolver protocol printer */
31
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35
36 #include "netdissect-stdinc.h"
37
38 #define ND_LONGJMP_FROM_TCHECK
39 #include "netdissect.h"
40 #include "addrtoname.h"
41 #include "extract.h"
42
43 #include "nameser.h"
44
45 /* BIND9 lib/lwres/include/lwres */
46 /*
47  * Use nd_uint16_t for lwres_uint16_t
48  * Use nd_uint32_t for lwres_uint32_t
49 */
50
51 struct lwres_lwpacket {
52         nd_uint32_t             length;
53         nd_uint16_t             version;
54         nd_uint16_t             pktflags;
55         nd_uint32_t             serial;
56         nd_uint32_t             opcode;
57         nd_uint32_t             result;
58         nd_uint32_t             recvlength;
59         nd_uint16_t             authtype;
60         nd_uint16_t             authlength;
61 };
62
63 #define LWRES_LWPACKETFLAG_RESPONSE     0x0001U /* if set, pkt is a response */
64
65 #define LWRES_LWPACKETVERSION_0         0
66
67 #define LWRES_FLAG_TRUSTNOTREQUIRED     0x00000001U
68 #define LWRES_FLAG_SECUREDATA           0x00000002U
69
70 /*
71  * no-op
72  */
73 #define LWRES_OPCODE_NOOP               0x00000000U
74
75 typedef struct {
76         /* public */
77         nd_uint16_t                     datalength;
78         /* data follows */
79 } lwres_nooprequest_t;
80
81 typedef struct {
82         /* public */
83         nd_uint16_t                     datalength;
84         /* data follows */
85 } lwres_noopresponse_t;
86
87 /*
88  * get addresses by name
89  */
90 #define LWRES_OPCODE_GETADDRSBYNAME     0x00010001U
91
92 typedef struct lwres_addr lwres_addr_t;
93
94 struct lwres_addr {
95         nd_uint32_t                     family;
96         nd_uint16_t                     length;
97         /* address follows */
98 };
99 #define LWRES_ADDR_LEN                  6
100
101 typedef struct {
102         /* public */
103         nd_uint32_t                     flags;
104         nd_uint32_t                     addrtypes;
105         nd_uint16_t                     namelen;
106         /* name follows */
107 } lwres_gabnrequest_t;
108 #define LWRES_GABNREQUEST_LEN           10
109
110 typedef struct {
111         /* public */
112         nd_uint32_t                     flags;
113         nd_uint16_t                     naliases;
114         nd_uint16_t                     naddrs;
115         nd_uint16_t                     realnamelen;
116         /* aliases follows */
117         /* addrs follows */
118         /* realname follows */
119 } lwres_gabnresponse_t;
120 #define LWRES_GABNRESPONSE_LEN          10
121
122 /*
123  * get name by address
124  */
125 #define LWRES_OPCODE_GETNAMEBYADDR      0x00010002U
126 typedef struct {
127         /* public */
128         nd_uint32_t                     flags;
129         /* addr follows */
130 } lwres_gnbarequest_t;
131 #define LWRES_GNBAREQUEST_LEN           4
132
133 typedef struct {
134         /* public */
135         nd_uint32_t                     flags;
136         nd_uint16_t                     naliases;
137         nd_uint16_t                     realnamelen;
138         /* aliases follows */
139         /* realname follows */
140 } lwres_gnbaresponse_t;
141 #define LWRES_GNBARESPONSE_LEN          8
142
143 /*
144  * get rdata by name
145  */
146 #define LWRES_OPCODE_GETRDATABYNAME     0x00010003U
147
148 typedef struct {
149         /* public */
150         nd_uint32_t                     flags;
151         nd_uint16_t                     rdclass;
152         nd_uint16_t                     rdtype;
153         nd_uint16_t                     namelen;
154         /* name follows */
155 } lwres_grbnrequest_t;
156 #define LWRES_GRBNREQUEST_LEN           10
157
158 typedef struct {
159         /* public */
160         nd_uint32_t                     flags;
161         nd_uint16_t                     rdclass;
162         nd_uint16_t                     rdtype;
163         nd_uint32_t                     ttl;
164         nd_uint16_t                     nrdatas;
165         nd_uint16_t                     nsigs;
166         /* realname here (len + name) */
167         /* rdata here (len + name) */
168         /* signatures here (len + name) */
169 } lwres_grbnresponse_t;
170 #define LWRES_GRBNRESPONSE_LEN          16
171
172 #define LWRDATA_VALIDATED       0x00000001
173
174 #define LWRES_ADDRTYPE_V4               0x00000001U     /* ipv4 */
175 #define LWRES_ADDRTYPE_V6               0x00000002U     /* ipv6 */
176
177 #define LWRES_MAX_ALIASES               16              /* max # of aliases */
178 #define LWRES_MAX_ADDRS                 64              /* max # of addrs */
179
180 static const struct tok opcode[] = {
181         { LWRES_OPCODE_NOOP,            "noop", },
182         { LWRES_OPCODE_GETADDRSBYNAME,  "getaddrsbyname", },
183         { LWRES_OPCODE_GETNAMEBYADDR,   "getnamebyaddr", },
184         { LWRES_OPCODE_GETRDATABYNAME,  "getrdatabyname", },
185         { 0,                            NULL, },
186 };
187
188 /* print-domain.c */
189 extern const struct tok ns_type2str[];
190 extern const struct tok ns_class2str[];
191
192 static unsigned
193 lwres_printname(netdissect_options *ndo,
194                 size_t l, const u_char *p0)
195 {
196         ND_PRINT(" ");
197         (void)nd_printn(ndo, p0, l, NULL);
198         p0 += l;
199         if (GET_U_1(p0))
200                 ND_PRINT(" (not NUL-terminated!)");
201         return l + 1;
202 }
203
204 static unsigned
205 lwres_printnamelen(netdissect_options *ndo,
206                    const u_char *p)
207 {
208         uint16_t l;
209         int advance;
210
211         l = GET_BE_U_2(p);
212         advance = lwres_printname(ndo, l, p + 2);
213         return 2 + advance;
214 }
215
216 static unsigned
217 lwres_printbinlen(netdissect_options *ndo,
218                   const u_char *p0)
219 {
220         const u_char *p;
221         uint16_t l;
222         int i;
223
224         p = p0;
225         l = GET_BE_U_2(p);
226         p += 2;
227         for (i = 0; i < l; i++) {
228                 ND_PRINT("%02x", GET_U_1(p));
229                 p++;
230         }
231         return 2 + l;
232 }
233
234 static int
235 lwres_printaddr(netdissect_options *ndo,
236                 const u_char *p0)
237 {
238         const u_char *p;
239         const lwres_addr_t *ap;
240         uint16_t l;
241         int i;
242
243         p = p0;
244         ap = (const lwres_addr_t *)p;
245         l = GET_BE_U_2(ap->length);
246         p += LWRES_ADDR_LEN;
247         ND_TCHECK_LEN(p, l);
248
249         switch (GET_BE_U_4(ap->family)) {
250         case 1: /* IPv4 */
251                 if (l < 4)
252                         return -1;
253                 ND_PRINT(" %s", GET_IPADDR_STRING(p));
254                 p += sizeof(nd_ipv4);
255                 break;
256         case 2: /* IPv6 */
257                 if (l < 16)
258                         return -1;
259                 ND_PRINT(" %s", GET_IP6ADDR_STRING(p));
260                 p += sizeof(nd_ipv6);
261                 break;
262         default:
263                 ND_PRINT(" %u/", GET_BE_U_4(ap->family));
264                 for (i = 0; i < l; i++) {
265                         ND_PRINT("%02x", GET_U_1(p));
266                         p++;
267                 }
268         }
269
270         return ND_BYTES_BETWEEN(p, p0);
271 }
272
273 void
274 lwres_print(netdissect_options *ndo,
275             const u_char *bp, u_int length)
276 {
277         const u_char *p;
278         const struct lwres_lwpacket *np;
279         uint32_t v;
280         const u_char *s;
281         int response;
282         int advance;
283         int unsupported = 0;
284
285         ndo->ndo_protocol = "lwres";
286         np = (const struct lwres_lwpacket *)bp;
287         ND_TCHECK_2(np->authlength);
288
289         ND_PRINT(" lwres");
290         v = GET_BE_U_2(np->version);
291         if (ndo->ndo_vflag || v != LWRES_LWPACKETVERSION_0)
292                 ND_PRINT(" v%u", v);
293         if (v != LWRES_LWPACKETVERSION_0) {
294                 s = bp + GET_BE_U_4(np->length);
295                 goto tail;
296         }
297
298         response = GET_BE_U_2(np->pktflags) & LWRES_LWPACKETFLAG_RESPONSE;
299
300         /* opcode and pktflags */
301         v = GET_BE_U_4(np->opcode);
302         ND_PRINT(" %s%s", tok2str(opcode, "#0x%x", v), response ? "" : "?");
303
304         /* pktflags */
305         v = GET_BE_U_2(np->pktflags);
306         if (v & ~LWRES_LWPACKETFLAG_RESPONSE)
307                 ND_PRINT("[0x%x]", v);
308
309         if (ndo->ndo_vflag > 1) {
310                 ND_PRINT(" ("); /*)*/
311                 ND_PRINT("serial:0x%x", GET_BE_U_4(np->serial));
312                 ND_PRINT(" result:0x%x", GET_BE_U_4(np->result));
313                 ND_PRINT(" recvlen:%u", GET_BE_U_4(np->recvlength));
314                 /* BIND910: not used */
315                 if (ndo->ndo_vflag > 2) {
316                         ND_PRINT(" authtype:0x%x", GET_BE_U_2(np->authtype));
317                         ND_PRINT(" authlen:%u", GET_BE_U_2(np->authlength));
318                 }
319                 /*(*/
320                 ND_PRINT(")");
321         }
322
323         /* per-opcode content */
324         if (!response) {
325                 /*
326                  * queries
327                  */
328                 const lwres_gabnrequest_t *gabn;
329                 const lwres_gnbarequest_t *gnba;
330                 const lwres_grbnrequest_t *grbn;
331                 uint32_t l;
332
333                 gabn = NULL;
334                 gnba = NULL;
335                 grbn = NULL;
336
337                 p = (const u_char *)(np + 1);
338                 switch (GET_BE_U_4(np->opcode)) {
339                 case LWRES_OPCODE_NOOP:
340                         s = p;
341                         break;
342                 case LWRES_OPCODE_GETADDRSBYNAME:
343                         gabn = (const lwres_gabnrequest_t *)p;
344                         ND_TCHECK_2(gabn->namelen);
345
346                         /* BIND910: not used */
347                         if (ndo->ndo_vflag > 2) {
348                                 ND_PRINT(" flags:0x%x",
349                                     GET_BE_U_4(gabn->flags));
350                         }
351
352                         v = GET_BE_U_4(gabn->addrtypes);
353                         switch (v & (LWRES_ADDRTYPE_V4 | LWRES_ADDRTYPE_V6)) {
354                         case LWRES_ADDRTYPE_V4:
355                                 ND_PRINT(" IPv4");
356                                 break;
357                         case LWRES_ADDRTYPE_V6:
358                                 ND_PRINT(" IPv6");
359                                 break;
360                         case LWRES_ADDRTYPE_V4 | LWRES_ADDRTYPE_V6:
361                                 ND_PRINT(" IPv4/6");
362                                 break;
363                         }
364                         if (v & ~(LWRES_ADDRTYPE_V4 | LWRES_ADDRTYPE_V6))
365                                 ND_PRINT("[0x%x]", v);
366
367                         s = p + LWRES_GABNREQUEST_LEN;
368                         l = GET_BE_U_2(gabn->namelen);
369                         advance = lwres_printname(ndo, l, s);
370                         s += advance;
371                         break;
372                 case LWRES_OPCODE_GETNAMEBYADDR:
373                         gnba = (const lwres_gnbarequest_t *)p;
374                         ND_TCHECK_4(gnba->flags);
375
376                         /* BIND910: not used */
377                         if (ndo->ndo_vflag > 2) {
378                                 ND_PRINT(" flags:0x%x",
379                                     GET_BE_U_4(gnba->flags));
380                         }
381
382                         s = p + LWRES_GNBAREQUEST_LEN;
383                         advance = lwres_printaddr(ndo, s);
384                         if (advance < 0)
385                                 goto invalid;
386                         s += advance;
387                         break;
388                 case LWRES_OPCODE_GETRDATABYNAME:
389                         /* XXX no trace, not tested */
390                         grbn = (const lwres_grbnrequest_t *)p;
391                         ND_TCHECK_2(grbn->namelen);
392
393                         /* BIND910: not used */
394                         if (ndo->ndo_vflag > 2) {
395                                 ND_PRINT(" flags:0x%x",
396                                     GET_BE_U_4(grbn->flags));
397                         }
398
399                         ND_PRINT(" %s", tok2str(ns_type2str, "Type%u",
400                             GET_BE_U_2(grbn->rdtype)));
401                         if (GET_BE_U_2(grbn->rdclass) != C_IN) {
402                                 ND_PRINT(" %s", tok2str(ns_class2str, "Class%u",
403                                     GET_BE_U_2(grbn->rdclass)));
404                         }
405
406                         s = p + LWRES_GRBNREQUEST_LEN;
407                         l = GET_BE_U_2(grbn->namelen);
408                         advance = lwres_printname(ndo, l, s);
409                         s += advance;
410                         break;
411                 default:
412                         s = p;
413                         unsupported++;
414                         break;
415                 }
416         } else {
417                 /*
418                  * responses
419                  */
420                 const lwres_gabnresponse_t *gabn;
421                 const lwres_gnbaresponse_t *gnba;
422                 const lwres_grbnresponse_t *grbn;
423                 uint32_t l, na;
424                 uint32_t i;
425
426                 gabn = NULL;
427                 gnba = NULL;
428                 grbn = NULL;
429
430                 p = (const u_char *)(np + 1);
431                 switch (GET_BE_U_4(np->opcode)) {
432                 case LWRES_OPCODE_NOOP:
433                         s = p;
434                         break;
435                 case LWRES_OPCODE_GETADDRSBYNAME:
436                         gabn = (const lwres_gabnresponse_t *)p;
437                         ND_TCHECK_2(gabn->realnamelen);
438
439                         /* BIND910: not used */
440                         if (ndo->ndo_vflag > 2) {
441                                 ND_PRINT(" flags:0x%x",
442                                     GET_BE_U_4(gabn->flags));
443                         }
444
445                         ND_PRINT(" %u/%u", GET_BE_U_2(gabn->naliases),
446                                   GET_BE_U_2(gabn->naddrs));
447
448                         s = p + LWRES_GABNRESPONSE_LEN;
449                         l = GET_BE_U_2(gabn->realnamelen);
450                         advance = lwres_printname(ndo, l, s);
451                         s += advance;
452
453                         /* aliases */
454                         na = GET_BE_U_2(gabn->naliases);
455                         for (i = 0; i < na; i++) {
456                                 advance = lwres_printnamelen(ndo, s);
457                                 s += advance;
458                         }
459
460                         /* addrs */
461                         na = GET_BE_U_2(gabn->naddrs);
462                         for (i = 0; i < na; i++) {
463                                 advance = lwres_printaddr(ndo, s);
464                                 if (advance < 0)
465                                         goto invalid;
466                                 s += advance;
467                         }
468                         break;
469                 case LWRES_OPCODE_GETNAMEBYADDR:
470                         gnba = (const lwres_gnbaresponse_t *)p;
471                         ND_TCHECK_2(gnba->realnamelen);
472
473                         /* BIND910: not used */
474                         if (ndo->ndo_vflag > 2) {
475                                 ND_PRINT(" flags:0x%x",
476                                     GET_BE_U_4(gnba->flags));
477                         }
478
479                         ND_PRINT(" %u", GET_BE_U_2(gnba->naliases));
480
481                         s = p + LWRES_GNBARESPONSE_LEN;
482                         l = GET_BE_U_2(gnba->realnamelen);
483                         advance = lwres_printname(ndo, l, s);
484                         s += advance;
485
486                         /* aliases */
487                         na = GET_BE_U_2(gnba->naliases);
488                         for (i = 0; i < na; i++) {
489                                 advance = lwres_printnamelen(ndo, s);
490                                 s += advance;
491                         }
492                         break;
493                 case LWRES_OPCODE_GETRDATABYNAME:
494                         /* XXX no trace, not tested */
495                         grbn = (const lwres_grbnresponse_t *)p;
496                         ND_TCHECK_2(grbn->nsigs);
497
498                         /* BIND910: not used */
499                         if (ndo->ndo_vflag > 2) {
500                                 ND_PRINT(" flags:0x%x",
501                                     GET_BE_U_4(grbn->flags));
502                         }
503
504                         ND_PRINT(" %s", tok2str(ns_type2str, "Type%u",
505                             GET_BE_U_2(grbn->rdtype)));
506                         if (GET_BE_U_2(grbn->rdclass) != C_IN) {
507                                 ND_PRINT(" %s", tok2str(ns_class2str, "Class%u",
508                                     GET_BE_U_2(grbn->rdclass)));
509                         }
510                         ND_PRINT(" TTL ");
511                         unsigned_relts_print(ndo,
512                                              GET_BE_U_4(grbn->ttl));
513                         ND_PRINT(" %u/%u", GET_BE_U_2(grbn->nrdatas),
514                                   GET_BE_U_2(grbn->nsigs));
515
516                         s = p + LWRES_GRBNRESPONSE_LEN;
517                         advance = lwres_printnamelen(ndo, s);
518                         s += advance;
519
520                         /* rdatas */
521                         na = GET_BE_U_2(grbn->nrdatas);
522                         for (i = 0; i < na; i++) {
523                                 /* XXX should decode resource data */
524                                 advance = lwres_printbinlen(ndo, s);
525                                 s += advance;
526                         }
527
528                         /* sigs */
529                         na = GET_BE_U_2(grbn->nsigs);
530                         for (i = 0; i < na; i++) {
531                                 /* XXX how should we print it? */
532                                 advance = lwres_printbinlen(ndo, s);
533                                 s += advance;
534                         }
535                         break;
536                 default:
537                         s = p;
538                         unsupported++;
539                         break;
540                 }
541         }
542
543   tail:
544         /* length mismatch */
545         if (GET_BE_U_4(np->length) != length) {
546                 ND_PRINT(" [len: %u != %u]", GET_BE_U_4(np->length),
547                           length);
548         }
549         if (!unsupported && s < bp + GET_BE_U_4(np->length))
550                 ND_PRINT("[extra]");
551         return;
552
553   invalid:
554         nd_print_invalid(ndo);
555 }