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.9 2024/09/02 16:15:32 christos Exp $"); 33 #endif 34 35 /* \summary: BIND9 Lightweight Resolver protocol printer */ 36 37 #include <config.h> 38 39 #include "netdissect-stdinc.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 follows */ 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 u_int 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(p0, p); 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 uint32_t pkt_len = GET_BE_U_4(np->length); 298 ND_TCHECK_LEN(bp, pkt_len); 299 s = bp + pkt_len; 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(bp, s) < GET_BE_U_4(np->length)) 555 ND_PRINT("[extra]"); 556 return; 557 558 invalid: 559 nd_print_invalid(ndo); 560 } 561