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