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