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