]> The Tcpdump Group git mirrors - tcpdump/blob - print-lwres.c
Squelch warnings from MSVC.
[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 #include <stdio.h>
39 #include <string.h>
40
41 #include "netdissect.h"
42 #include "addrtoname.h"
43 #include "extract.h"
44
45 #include "nameser.h"
46
47 /* BIND9 lib/lwres/include/lwres */
48 /*
49 * Use nd_uint16_t for lwres_uint16_t
50 * Use nd_uint32_t for lwres_uint32_t
51 */
52
53 struct lwres_lwpacket {
54 nd_uint32_t length;
55 nd_uint16_t version;
56 nd_uint16_t pktflags;
57 nd_uint32_t serial;
58 nd_uint32_t opcode;
59 nd_uint32_t result;
60 nd_uint32_t recvlength;
61 nd_uint16_t authtype;
62 nd_uint16_t authlength;
63 };
64
65 #define LWRES_LWPACKETFLAG_RESPONSE 0x0001U /* if set, pkt is a response */
66
67 #define LWRES_LWPACKETVERSION_0 0
68
69 #define LWRES_FLAG_TRUSTNOTREQUIRED 0x00000001U
70 #define LWRES_FLAG_SECUREDATA 0x00000002U
71
72 /*
73 * no-op
74 */
75 #define LWRES_OPCODE_NOOP 0x00000000U
76
77 typedef struct {
78 /* public */
79 nd_uint16_t datalength;
80 /* data follows */
81 } lwres_nooprequest_t;
82
83 typedef struct {
84 /* public */
85 nd_uint16_t datalength;
86 /* data follows */
87 } lwres_noopresponse_t;
88
89 /*
90 * get addresses by name
91 */
92 #define LWRES_OPCODE_GETADDRSBYNAME 0x00010001U
93
94 typedef struct lwres_addr lwres_addr_t;
95
96 struct lwres_addr {
97 nd_uint32_t family;
98 nd_uint16_t length;
99 /* address folows */
100 };
101 #define LWRES_ADDR_LEN 6
102
103 typedef struct {
104 /* public */
105 nd_uint32_t flags;
106 nd_uint32_t addrtypes;
107 nd_uint16_t namelen;
108 /* name follows */
109 } lwres_gabnrequest_t;
110 #define LWRES_GABNREQUEST_LEN 10
111
112 typedef struct {
113 /* public */
114 nd_uint32_t flags;
115 nd_uint16_t naliases;
116 nd_uint16_t naddrs;
117 nd_uint16_t realnamelen;
118 /* aliases follows */
119 /* addrs follows */
120 /* realname follows */
121 } lwres_gabnresponse_t;
122 #define LWRES_GABNRESPONSE_LEN 10
123
124 /*
125 * get name by address
126 */
127 #define LWRES_OPCODE_GETNAMEBYADDR 0x00010002U
128 typedef struct {
129 /* public */
130 nd_uint32_t flags;
131 /* addr follows */
132 } lwres_gnbarequest_t;
133 #define LWRES_GNBAREQUEST_LEN 4
134
135 typedef struct {
136 /* public */
137 nd_uint32_t flags;
138 nd_uint16_t naliases;
139 nd_uint16_t realnamelen;
140 /* aliases follows */
141 /* realname follows */
142 } lwres_gnbaresponse_t;
143 #define LWRES_GNBARESPONSE_LEN 8
144
145 /*
146 * get rdata by name
147 */
148 #define LWRES_OPCODE_GETRDATABYNAME 0x00010003U
149
150 typedef struct {
151 /* public */
152 nd_uint32_t flags;
153 nd_uint16_t rdclass;
154 nd_uint16_t rdtype;
155 nd_uint16_t namelen;
156 /* name follows */
157 } lwres_grbnrequest_t;
158 #define LWRES_GRBNREQUEST_LEN 10
159
160 typedef struct {
161 /* public */
162 nd_uint32_t flags;
163 nd_uint16_t rdclass;
164 nd_uint16_t rdtype;
165 nd_uint32_t ttl;
166 nd_uint16_t nrdatas;
167 nd_uint16_t nsigs;
168 /* realname here (len + name) */
169 /* rdata here (len + name) */
170 /* signatures here (len + name) */
171 } lwres_grbnresponse_t;
172 #define LWRES_GRBNRESPONSE_LEN 16
173
174 #define LWRDATA_VALIDATED 0x00000001
175
176 #define LWRES_ADDRTYPE_V4 0x00000001U /* ipv4 */
177 #define LWRES_ADDRTYPE_V6 0x00000002U /* ipv6 */
178
179 #define LWRES_MAX_ALIASES 16 /* max # of aliases */
180 #define LWRES_MAX_ADDRS 64 /* max # of addrs */
181
182 static const struct tok opcode[] = {
183 { LWRES_OPCODE_NOOP, "noop", },
184 { LWRES_OPCODE_GETADDRSBYNAME, "getaddrsbyname", },
185 { LWRES_OPCODE_GETNAMEBYADDR, "getnamebyaddr", },
186 { LWRES_OPCODE_GETRDATABYNAME, "getrdatabyname", },
187 { 0, NULL, },
188 };
189
190 /* print-domain.c */
191 extern const struct tok ns_type2str[];
192 extern const struct tok ns_class2str[];
193
194 static int
195 lwres_printname(netdissect_options *ndo,
196 size_t l, const u_char *p0)
197 {
198 const u_char *p;
199 size_t i;
200
201 p = p0;
202 /* + 1 for terminating \0 */
203 if (p + l + 1 > ndo->ndo_snapend)
204 goto trunc;
205
206 ND_PRINT(" ");
207 for (i = 0; i < l; i++)
208 safeputchar(ndo, *p++);
209 p++; /* skip terminating \0 */
210
211 return p - p0;
212
213 trunc:
214 return -1;
215 }
216
217 static int
218 lwres_printnamelen(netdissect_options *ndo,
219 const u_char *p)
220 {
221 uint16_t l;
222 int advance;
223
224 if (p + 2 > ndo->ndo_snapend)
225 goto trunc;
226 l = EXTRACT_BE_U_2(p);
227 advance = lwres_printname(ndo, l, p + 2);
228 if (advance < 0)
229 goto trunc;
230 return 2 + advance;
231
232 trunc:
233 return -1;
234 }
235
236 static int
237 lwres_printbinlen(netdissect_options *ndo,
238 const u_char *p0)
239 {
240 const u_char *p;
241 uint16_t l;
242 int i;
243
244 p = p0;
245 if (p + 2 > ndo->ndo_snapend)
246 goto trunc;
247 l = EXTRACT_BE_U_2(p);
248 if (p + 2 + l > ndo->ndo_snapend)
249 goto trunc;
250 p += 2;
251 for (i = 0; i < l; i++)
252 ND_PRINT("%02x", *p++);
253 return p - p0;
254
255 trunc:
256 return -1;
257 }
258
259 static int
260 lwres_printaddr(netdissect_options *ndo,
261 const u_char *p0)
262 {
263 const u_char *p;
264 const lwres_addr_t *ap;
265 uint16_t l;
266 int i;
267
268 p = p0;
269 ap = (const lwres_addr_t *)p;
270 ND_TCHECK_2(ap->length);
271 l = EXTRACT_BE_U_2(ap->length);
272 p += LWRES_ADDR_LEN;
273 ND_TCHECK_LEN(p, l);
274
275 switch (EXTRACT_BE_U_4(ap->family)) {
276 case 1: /* IPv4 */
277 if (l < 4)
278 return -1;
279 ND_PRINT(" %s", ipaddr_string(ndo, p));
280 p += sizeof(struct in_addr);
281 break;
282 case 2: /* IPv6 */
283 if (l < 16)
284 return -1;
285 ND_PRINT(" %s", ip6addr_string(ndo, p));
286 p += sizeof(struct in6_addr);
287 break;
288 default:
289 ND_PRINT(" %u/", EXTRACT_BE_U_4(ap->family));
290 for (i = 0; i < l; i++)
291 ND_PRINT("%02x", *p++);
292 }
293
294 return p - p0;
295
296 trunc:
297 return -1;
298 }
299
300 void
301 lwres_print(netdissect_options *ndo,
302 const u_char *bp, u_int length)
303 {
304 const u_char *p;
305 const struct lwres_lwpacket *np;
306 uint32_t v;
307 const u_char *s;
308 int response;
309 int advance;
310 int unsupported = 0;
311
312 np = (const struct lwres_lwpacket *)bp;
313 ND_TCHECK_2(np->authlength);
314
315 ND_PRINT(" lwres");
316 v = EXTRACT_BE_U_2(np->version);
317 if (ndo->ndo_vflag || v != LWRES_LWPACKETVERSION_0)
318 ND_PRINT(" v%u", v);
319 if (v != LWRES_LWPACKETVERSION_0) {
320 s = bp + EXTRACT_BE_U_4(np->length);
321 goto tail;
322 }
323
324 response = EXTRACT_BE_U_2(np->pktflags) & LWRES_LWPACKETFLAG_RESPONSE;
325
326 /* opcode and pktflags */
327 v = EXTRACT_BE_U_4(np->opcode);
328 ND_PRINT(" %s%s", tok2str(opcode, "#0x%x", v), response ? "" : "?");
329
330 /* pktflags */
331 v = EXTRACT_BE_U_2(np->pktflags);
332 if (v & ~LWRES_LWPACKETFLAG_RESPONSE)
333 ND_PRINT("[0x%x]", v);
334
335 if (ndo->ndo_vflag > 1) {
336 ND_PRINT(" ("); /*)*/
337 ND_PRINT("serial:0x%x", EXTRACT_BE_U_4(np->serial));
338 ND_PRINT(" result:0x%x", EXTRACT_BE_U_4(np->result));
339 ND_PRINT(" recvlen:%u", EXTRACT_BE_U_4(np->recvlength));
340 /* BIND910: not used */
341 if (ndo->ndo_vflag > 2) {
342 ND_PRINT(" authtype:0x%x", EXTRACT_BE_U_2(np->authtype));
343 ND_PRINT(" authlen:%u", EXTRACT_BE_U_2(np->authlength));
344 }
345 /*(*/
346 ND_PRINT(")");
347 }
348
349 /* per-opcode content */
350 if (!response) {
351 /*
352 * queries
353 */
354 const lwres_gabnrequest_t *gabn;
355 const lwres_gnbarequest_t *gnba;
356 const lwres_grbnrequest_t *grbn;
357 uint32_t l;
358
359 gabn = NULL;
360 gnba = NULL;
361 grbn = NULL;
362
363 p = (const u_char *)(np + 1);
364 switch (EXTRACT_BE_U_4(np->opcode)) {
365 case LWRES_OPCODE_NOOP:
366 s = p;
367 break;
368 case LWRES_OPCODE_GETADDRSBYNAME:
369 gabn = (const lwres_gabnrequest_t *)p;
370 ND_TCHECK_2(gabn->namelen);
371
372 /* BIND910: not used */
373 if (ndo->ndo_vflag > 2) {
374 ND_PRINT(" flags:0x%x",
375 EXTRACT_BE_U_4(gabn->flags));
376 }
377
378 v = EXTRACT_BE_U_4(gabn->addrtypes);
379 switch (v & (LWRES_ADDRTYPE_V4 | LWRES_ADDRTYPE_V6)) {
380 case LWRES_ADDRTYPE_V4:
381 ND_PRINT(" IPv4");
382 break;
383 case LWRES_ADDRTYPE_V6:
384 ND_PRINT(" IPv6");
385 break;
386 case LWRES_ADDRTYPE_V4 | LWRES_ADDRTYPE_V6:
387 ND_PRINT(" IPv4/6");
388 break;
389 }
390 if (v & ~(LWRES_ADDRTYPE_V4 | LWRES_ADDRTYPE_V6))
391 ND_PRINT("[0x%x]", v);
392
393 s = p + LWRES_GABNREQUEST_LEN;
394 l = EXTRACT_BE_U_2(gabn->namelen);
395 advance = lwres_printname(ndo, l, s);
396 if (advance < 0)
397 goto trunc;
398 s += advance;
399 break;
400 case LWRES_OPCODE_GETNAMEBYADDR:
401 gnba = (const lwres_gnbarequest_t *)p;
402 ND_TCHECK_4(gnba->flags);
403
404 /* BIND910: not used */
405 if (ndo->ndo_vflag > 2) {
406 ND_PRINT(" flags:0x%x",
407 EXTRACT_BE_U_4(gnba->flags));
408 }
409
410 s = p + LWRES_GNBAREQUEST_LEN;
411 advance = lwres_printaddr(ndo, s);
412 if (advance < 0)
413 goto trunc;
414 s += advance;
415 break;
416 case LWRES_OPCODE_GETRDATABYNAME:
417 /* XXX no trace, not tested */
418 grbn = (const lwres_grbnrequest_t *)p;
419 ND_TCHECK_2(grbn->namelen);
420
421 /* BIND910: not used */
422 if (ndo->ndo_vflag > 2) {
423 ND_PRINT(" flags:0x%x",
424 EXTRACT_BE_U_4(grbn->flags));
425 }
426
427 ND_PRINT(" %s", tok2str(ns_type2str, "Type%u",
428 EXTRACT_BE_U_2(grbn->rdtype)));
429 if (EXTRACT_BE_U_2(grbn->rdclass) != C_IN) {
430 ND_PRINT(" %s", tok2str(ns_class2str, "Class%u",
431 EXTRACT_BE_U_2(grbn->rdclass)));
432 }
433
434 s = p + LWRES_GRBNREQUEST_LEN;
435 l = EXTRACT_BE_U_2(grbn->namelen);
436 advance = lwres_printname(ndo, l, s);
437 if (advance < 0)
438 goto trunc;
439 s += advance;
440 break;
441 default:
442 s = p;
443 unsupported++;
444 break;
445 }
446 } else {
447 /*
448 * responses
449 */
450 const lwres_gabnresponse_t *gabn;
451 const lwres_gnbaresponse_t *gnba;
452 const lwres_grbnresponse_t *grbn;
453 uint32_t l, na;
454 uint32_t i;
455
456 gabn = NULL;
457 gnba = NULL;
458 grbn = NULL;
459
460 p = (const u_char *)(np + 1);
461 switch (EXTRACT_BE_U_4(np->opcode)) {
462 case LWRES_OPCODE_NOOP:
463 s = p;
464 break;
465 case LWRES_OPCODE_GETADDRSBYNAME:
466 gabn = (const lwres_gabnresponse_t *)p;
467 ND_TCHECK_2(gabn->realnamelen);
468
469 /* BIND910: not used */
470 if (ndo->ndo_vflag > 2) {
471 ND_PRINT(" flags:0x%x",
472 EXTRACT_BE_U_4(gabn->flags));
473 }
474
475 ND_PRINT(" %u/%u", EXTRACT_BE_U_2(gabn->naliases),
476 EXTRACT_BE_U_2(gabn->naddrs));
477
478 s = p + LWRES_GABNRESPONSE_LEN;
479 l = EXTRACT_BE_U_2(gabn->realnamelen);
480 advance = lwres_printname(ndo, l, s);
481 if (advance < 0)
482 goto trunc;
483 s += advance;
484
485 /* aliases */
486 na = EXTRACT_BE_U_2(gabn->naliases);
487 for (i = 0; i < na; i++) {
488 advance = lwres_printnamelen(ndo, s);
489 if (advance < 0)
490 goto trunc;
491 s += advance;
492 }
493
494 /* addrs */
495 na = EXTRACT_BE_U_2(gabn->naddrs);
496 for (i = 0; i < na; i++) {
497 advance = lwres_printaddr(ndo, s);
498 if (advance < 0)
499 goto trunc;
500 s += advance;
501 }
502 break;
503 case LWRES_OPCODE_GETNAMEBYADDR:
504 gnba = (const lwres_gnbaresponse_t *)p;
505 ND_TCHECK_2(gnba->realnamelen);
506
507 /* BIND910: not used */
508 if (ndo->ndo_vflag > 2) {
509 ND_PRINT(" flags:0x%x",
510 EXTRACT_BE_U_4(gnba->flags));
511 }
512
513 ND_PRINT(" %u", EXTRACT_BE_U_2(gnba->naliases));
514
515 s = p + LWRES_GNBARESPONSE_LEN;
516 l = EXTRACT_BE_U_2(gnba->realnamelen);
517 advance = lwres_printname(ndo, l, s);
518 if (advance < 0)
519 goto trunc;
520 s += advance;
521
522 /* aliases */
523 na = EXTRACT_BE_U_2(gnba->naliases);
524 for (i = 0; i < na; i++) {
525 advance = lwres_printnamelen(ndo, s);
526 if (advance < 0)
527 goto trunc;
528 s += advance;
529 }
530 break;
531 case LWRES_OPCODE_GETRDATABYNAME:
532 /* XXX no trace, not tested */
533 grbn = (const lwres_grbnresponse_t *)p;
534 ND_TCHECK_2(grbn->nsigs);
535
536 /* BIND910: not used */
537 if (ndo->ndo_vflag > 2) {
538 ND_PRINT(" flags:0x%x",
539 EXTRACT_BE_U_4(grbn->flags));
540 }
541
542 ND_PRINT(" %s", tok2str(ns_type2str, "Type%u",
543 EXTRACT_BE_U_2(grbn->rdtype)));
544 if (EXTRACT_BE_U_2(grbn->rdclass) != C_IN) {
545 ND_PRINT(" %s", tok2str(ns_class2str, "Class%u",
546 EXTRACT_BE_U_2(grbn->rdclass)));
547 }
548 ND_PRINT(" TTL ");
549 unsigned_relts_print(ndo,
550 EXTRACT_BE_U_4(grbn->ttl));
551 ND_PRINT(" %u/%u", EXTRACT_BE_U_2(grbn->nrdatas),
552 EXTRACT_BE_U_2(grbn->nsigs));
553
554 s = p + LWRES_GRBNRESPONSE_LEN;
555 advance = lwres_printnamelen(ndo, s);
556 if (advance < 0)
557 goto trunc;
558 s += advance;
559
560 /* rdatas */
561 na = EXTRACT_BE_U_2(grbn->nrdatas);
562 for (i = 0; i < na; i++) {
563 /* XXX should decode resource data */
564 advance = lwres_printbinlen(ndo, s);
565 if (advance < 0)
566 goto trunc;
567 s += advance;
568 }
569
570 /* sigs */
571 na = EXTRACT_BE_U_2(grbn->nsigs);
572 for (i = 0; i < na; i++) {
573 /* XXX how should we print it? */
574 advance = lwres_printbinlen(ndo, s);
575 if (advance < 0)
576 goto trunc;
577 s += advance;
578 }
579 break;
580 default:
581 s = p;
582 unsupported++;
583 break;
584 }
585 }
586
587 tail:
588 /* length mismatch */
589 if (EXTRACT_BE_U_4(np->length) != length) {
590 ND_PRINT(" [len: %u != %u]", EXTRACT_BE_U_4(np->length),
591 length);
592 }
593 if (!unsupported && s < bp + EXTRACT_BE_U_4(np->length))
594 ND_PRINT("[extra]");
595 return;
596
597 trunc:
598 ND_PRINT("[|lwres]");
599 }