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