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 #include <config.h> 33 34 #include "netdissect-stdinc.h" 35 36 #define ND_LONGJMP_FROM_TCHECK 37 #include "netdissect.h" 38 #include "addrtoname.h" 39 #include "extract.h" 40 41 #include "nameser.h" 42 43 /* BIND9 lib/lwres/include/lwres */ 44 /* 45 * Use nd_uint16_t for lwres_uint16_t 46 * Use nd_uint32_t for lwres_uint32_t 47 */ 48 49 struct lwres_lwpacket { 50 nd_uint32_t length; 51 nd_uint16_t version; 52 nd_uint16_t pktflags; 53 nd_uint32_t serial; 54 nd_uint32_t opcode; 55 nd_uint32_t result; 56 nd_uint32_t recvlength; 57 nd_uint16_t authtype; 58 nd_uint16_t authlength; 59 }; 60 61 #define LWRES_LWPACKETFLAG_RESPONSE 0x0001U /* if set, pkt is a response */ 62 63 #define LWRES_LWPACKETVERSION_0 0 64 65 #define LWRES_FLAG_TRUSTNOTREQUIRED 0x00000001U 66 #define LWRES_FLAG_SECUREDATA 0x00000002U 67 68 /* 69 * no-op 70 */ 71 #define LWRES_OPCODE_NOOP 0x00000000U 72 73 typedef struct { 74 /* public */ 75 nd_uint16_t datalength; 76 /* data follows */ 77 } lwres_nooprequest_t; 78 79 typedef struct { 80 /* public */ 81 nd_uint16_t datalength; 82 /* data follows */ 83 } lwres_noopresponse_t; 84 85 /* 86 * get addresses by name 87 */ 88 #define LWRES_OPCODE_GETADDRSBYNAME 0x00010001U 89 90 typedef struct lwres_addr lwres_addr_t; 91 92 struct lwres_addr { 93 nd_uint32_t family; 94 nd_uint16_t length; 95 /* address follows */ 96 }; 97 #define LWRES_ADDR_LEN 6 98 99 typedef struct { 100 /* public */ 101 nd_uint32_t flags; 102 nd_uint32_t addrtypes; 103 nd_uint16_t namelen; 104 /* name follows */ 105 } lwres_gabnrequest_t; 106 #define LWRES_GABNREQUEST_LEN 10 107 108 typedef struct { 109 /* public */ 110 nd_uint32_t flags; 111 nd_uint16_t naliases; 112 nd_uint16_t naddrs; 113 nd_uint16_t realnamelen; 114 /* aliases follows */ 115 /* addrs follows */ 116 /* realname follows */ 117 } lwres_gabnresponse_t; 118 #define LWRES_GABNRESPONSE_LEN 10 119 120 /* 121 * get name by address 122 */ 123 #define LWRES_OPCODE_GETNAMEBYADDR 0x00010002U 124 typedef struct { 125 /* public */ 126 nd_uint32_t flags; 127 /* addr follows */ 128 } lwres_gnbarequest_t; 129 #define LWRES_GNBAREQUEST_LEN 4 130 131 typedef struct { 132 /* public */ 133 nd_uint32_t flags; 134 nd_uint16_t naliases; 135 nd_uint16_t realnamelen; 136 /* aliases follows */ 137 /* realname follows */ 138 } lwres_gnbaresponse_t; 139 #define LWRES_GNBARESPONSE_LEN 8 140 141 /* 142 * get rdata by name 143 */ 144 #define LWRES_OPCODE_GETRDATABYNAME 0x00010003U 145 146 typedef struct { 147 /* public */ 148 nd_uint32_t flags; 149 nd_uint16_t rdclass; 150 nd_uint16_t rdtype; 151 nd_uint16_t namelen; 152 /* name follows */ 153 } lwres_grbnrequest_t; 154 #define LWRES_GRBNREQUEST_LEN 10 155 156 typedef struct { 157 /* public */ 158 nd_uint32_t flags; 159 nd_uint16_t rdclass; 160 nd_uint16_t rdtype; 161 nd_uint32_t ttl; 162 nd_uint16_t nrdatas; 163 nd_uint16_t nsigs; 164 /* realname here (len + name) */ 165 /* rdata here (len + name) */ 166 /* signatures here (len + name) */ 167 } lwres_grbnresponse_t; 168 #define LWRES_GRBNRESPONSE_LEN 16 169 170 #define LWRDATA_VALIDATED 0x00000001 171 172 #define LWRES_ADDRTYPE_V4 0x00000001U /* ipv4 */ 173 #define LWRES_ADDRTYPE_V6 0x00000002U /* ipv6 */ 174 175 #define LWRES_MAX_ALIASES 16 /* max # of aliases */ 176 #define LWRES_MAX_ADDRS 64 /* max # of addrs */ 177 178 static const struct tok opcode[] = { 179 { LWRES_OPCODE_NOOP, "noop", }, 180 { LWRES_OPCODE_GETADDRSBYNAME, "getaddrsbyname", }, 181 { LWRES_OPCODE_GETNAMEBYADDR, "getnamebyaddr", }, 182 { LWRES_OPCODE_GETRDATABYNAME, "getrdatabyname", }, 183 { 0, NULL, }, 184 }; 185 186 /* print-domain.c */ 187 extern const struct tok ns_type2str[]; 188 extern const struct tok ns_class2str[]; 189 190 static unsigned 191 lwres_printname(netdissect_options *ndo, 192 u_int l, const u_char *p0) 193 { 194 ND_PRINT(" "); 195 (void)nd_printn(ndo, p0, l, NULL); 196 p0 += l; 197 if (GET_U_1(p0)) 198 ND_PRINT(" (not NUL-terminated!)"); 199 return l + 1; 200 } 201 202 static unsigned 203 lwres_printnamelen(netdissect_options *ndo, 204 const u_char *p) 205 { 206 uint16_t l; 207 int advance; 208 209 l = GET_BE_U_2(p); 210 advance = lwres_printname(ndo, l, p + 2); 211 return 2 + advance; 212 } 213 214 static unsigned 215 lwres_printbinlen(netdissect_options *ndo, 216 const u_char *p0) 217 { 218 const u_char *p; 219 uint16_t l; 220 int i; 221 222 p = p0; 223 l = GET_BE_U_2(p); 224 p += 2; 225 for (i = 0; i < l; i++) { 226 ND_PRINT("%02x", GET_U_1(p)); 227 p++; 228 } 229 return 2 + l; 230 } 231 232 static int 233 lwres_printaddr(netdissect_options *ndo, 234 const u_char *p0) 235 { 236 const u_char *p; 237 const lwres_addr_t *ap; 238 uint16_t l; 239 int i; 240 241 p = p0; 242 ap = (const lwres_addr_t *)p; 243 l = GET_BE_U_2(ap->length); 244 p += LWRES_ADDR_LEN; 245 ND_TCHECK_LEN(p, l); 246 247 switch (GET_BE_U_4(ap->family)) { 248 case 1: /* IPv4 */ 249 if (l < 4) 250 return -1; 251 ND_PRINT(" %s", GET_IPADDR_STRING(p)); 252 p += sizeof(nd_ipv4); 253 break; 254 case 2: /* IPv6 */ 255 if (l < 16) 256 return -1; 257 ND_PRINT(" %s", GET_IP6ADDR_STRING(p)); 258 p += sizeof(nd_ipv6); 259 break; 260 default: 261 ND_PRINT(" %u/", GET_BE_U_4(ap->family)); 262 for (i = 0; i < l; i++) { 263 ND_PRINT("%02x", GET_U_1(p)); 264 p++; 265 } 266 } 267 268 return ND_BYTES_BETWEEN(p0, p); 269 } 270 271 void 272 lwres_print(netdissect_options *ndo, 273 const u_char *bp, u_int length) 274 { 275 const u_char *p; 276 const struct lwres_lwpacket *np; 277 uint32_t v; 278 const u_char *s; 279 int response; 280 int advance; 281 int unsupported = 0; 282 283 ndo->ndo_protocol = "lwres"; 284 np = (const struct lwres_lwpacket *)bp; 285 ND_TCHECK_2(np->authlength); 286 287 ND_PRINT(" lwres"); 288 v = GET_BE_U_2(np->version); 289 if (ndo->ndo_vflag || v != LWRES_LWPACKETVERSION_0) 290 ND_PRINT(" v%u", v); 291 if (v != LWRES_LWPACKETVERSION_0) { 292 uint32_t pkt_len = GET_BE_U_4(np->length); 293 ND_TCHECK_LEN(bp, pkt_len); 294 s = bp + pkt_len; 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(bp, s) < GET_BE_U_4(np->length)) 550 ND_PRINT("[extra]"); 551 return; 552 553 invalid: 554 nd_print_invalid(ndo); 555 } 556