1 /* 2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (c) 1996-1999 by Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /* Imports. */ 19 20 #include "port_before.h" 21 22 #include <sys/param.h> 23 #include <sys/socket.h> 24 25 #include <netinet/in.h> 26 #include <arpa/inet.h> 27 #include <arpa/nameser.h> 28 29 #include <ctype.h> 30 #include <errno.h> 31 #include <netdb.h> 32 #include <resolv.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 37 #include <isc/memcluster.h> 38 #include <irs.h> 39 40 #include "port_after.h" 41 42 #include "irs_p.h" 43 #include "dns_p.h" 44 45 #ifdef SPRINTF_CHAR 46 # define SPRINTF(x) strlen(sprintf/**/x) 47 #else 48 # define SPRINTF(x) sprintf x 49 #endif 50 51 /* Definitions. */ 52 53 #define MAXALIASES 35 54 55 #define MAXPACKET (64*1024) 56 57 struct pvt { 58 struct nwent net; 59 char * ali[MAXALIASES]; 60 char buf[BUFSIZ+1]; 61 struct __res_state * res; 62 void (*free_res)(void *); 63 }; 64 65 typedef union { 66 long al; 67 char ac; 68 } align; 69 70 enum by_what { by_addr, by_name }; 71 72 /* Forwards. */ 73 74 static void nw_close(struct irs_nw *); 75 static struct nwent * nw_byname(struct irs_nw *, const char *, int); 76 static struct nwent * nw_byaddr(struct irs_nw *, void *, int, int); 77 static struct nwent * nw_next(struct irs_nw *); 78 static void nw_rewind(struct irs_nw *); 79 static void nw_minimize(struct irs_nw *); 80 static struct __res_state * nw_res_get(struct irs_nw *this); 81 static void nw_res_set(struct irs_nw *this, 82 struct __res_state *res, 83 void (*free_res)(void *)); 84 85 static struct nwent * get1101byaddr(struct irs_nw *, u_char *, int); 86 static struct nwent * get1101byname(struct irs_nw *, const char *); 87 static struct nwent * get1101answer(struct irs_nw *, 88 u_char *ansbuf, int anslen, 89 enum by_what by_what, 90 int af, const char *name, 91 const u_char *addr, int addrlen); 92 static struct nwent * get1101mask(struct irs_nw *this, struct nwent *); 93 static int make1101inaddr(const u_char *, int, char *, int); 94 static void normalize_name(char *name); 95 static int init(struct irs_nw *this); 96 97 /* Exports. */ 98 99 struct irs_nw * 100 irs_dns_nw(struct irs_acc *this) { 101 struct irs_nw *nw; 102 struct pvt *pvt; 103 104 UNUSED(this); 105 106 if (!(pvt = memget(sizeof *pvt))) { 107 errno = ENOMEM; 108 return (NULL); 109 } 110 memset(pvt, 0, sizeof *pvt); 111 if (!(nw = memget(sizeof *nw))) { 112 memput(pvt, sizeof *pvt); 113 errno = ENOMEM; 114 return (NULL); 115 } 116 memset(nw, 0x5e, sizeof *nw); 117 nw->private = pvt; 118 nw->close = nw_close; 119 nw->byname = nw_byname; 120 nw->byaddr = nw_byaddr; 121 nw->next = nw_next; 122 nw->rewind = nw_rewind; 123 nw->minimize = nw_minimize; 124 nw->res_get = nw_res_get; 125 nw->res_set = nw_res_set; 126 return (nw); 127 } 128 129 /* Methods. */ 130 131 static void 132 nw_close(struct irs_nw *this) { 133 struct pvt *pvt = (struct pvt *)this->private; 134 135 nw_minimize(this); 136 137 if (pvt->res && pvt->free_res) 138 (*pvt->free_res)(pvt->res); 139 140 memput(pvt, sizeof *pvt); 141 memput(this, sizeof *this); 142 } 143 144 static struct nwent * 145 nw_byname(struct irs_nw *this, const char *name, int af) { 146 struct pvt *pvt = (struct pvt *)this->private; 147 148 if (init(this) == -1) 149 return (NULL); 150 151 switch (af) { 152 case AF_INET: 153 return (get1101byname(this, name)); 154 default: 155 (void)NULL; 156 } 157 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); 158 errno = EAFNOSUPPORT; 159 return (NULL); 160 } 161 162 static struct nwent * 163 nw_byaddr(struct irs_nw *this, void *net, int len, int af) { 164 struct pvt *pvt = (struct pvt *)this->private; 165 166 if (init(this) == -1) 167 return (NULL); 168 169 switch (af) { 170 case AF_INET: 171 return (get1101byaddr(this, net, len)); 172 default: 173 (void)NULL; 174 } 175 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); 176 errno = EAFNOSUPPORT; 177 return (NULL); 178 } 179 180 static struct nwent * 181 nw_next(struct irs_nw *this) { 182 183 UNUSED(this); 184 185 return (NULL); 186 } 187 188 static void 189 nw_rewind(struct irs_nw *this) { 190 UNUSED(this); 191 /* NOOP */ 192 } 193 194 static void 195 nw_minimize(struct irs_nw *this) { 196 struct pvt *pvt = (struct pvt *)this->private; 197 198 if (pvt->res) 199 res_nclose(pvt->res); 200 } 201 202 static struct __res_state * 203 nw_res_get(struct irs_nw *this) { 204 struct pvt *pvt = (struct pvt *)this->private; 205 206 if (!pvt->res) { 207 struct __res_state *res; 208 res = (struct __res_state *)malloc(sizeof *res); 209 if (!res) { 210 errno = ENOMEM; 211 return (NULL); 212 } 213 memset(res, 0, sizeof *res); 214 nw_res_set(this, res, free); 215 } 216 217 return (pvt->res); 218 } 219 220 static void 221 nw_res_set(struct irs_nw *this, struct __res_state *res, 222 void (*free_res)(void *)) { 223 struct pvt *pvt = (struct pvt *)this->private; 224 225 if (pvt->res && pvt->free_res) { 226 res_nclose(pvt->res); 227 (*pvt->free_res)(pvt->res); 228 } 229 230 pvt->res = res; 231 pvt->free_res = free_res; 232 } 233 234 /* Private. */ 235 236 static struct nwent * 237 get1101byname(struct irs_nw *this, const char *name) { 238 struct pvt *pvt = (struct pvt *)this->private; 239 u_char *ansbuf; 240 int anslen; 241 struct nwent *result; 242 243 ansbuf = memget(MAXPACKET); 244 if (ansbuf == NULL) { 245 errno = ENOMEM; 246 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); 247 return (NULL); 248 } 249 anslen = res_nsearch(pvt->res, name, C_IN, T_PTR, ansbuf, MAXPACKET); 250 if (anslen < 0) { 251 memput(ansbuf, MAXPACKET); 252 return (NULL); 253 } 254 result = get1101mask(this, get1101answer(this, ansbuf, anslen, by_name, 255 AF_INET, name, NULL, 0)); 256 memput(ansbuf, MAXPACKET); 257 return (result); 258 } 259 260 static struct nwent * 261 get1101byaddr(struct irs_nw *this, u_char *net, int len) { 262 struct pvt *pvt = (struct pvt *)this->private; 263 char qbuf[sizeof "255.255.255.255.in-addr.arpa"]; 264 struct nwent *result; 265 u_char *ansbuf; 266 int anslen; 267 268 if (len < 1 || len > 32) { 269 errno = EINVAL; 270 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); 271 return (NULL); 272 } 273 if (make1101inaddr(net, len, qbuf, sizeof qbuf) < 0) 274 return (NULL); 275 ansbuf = memget(MAXPACKET); 276 if (ansbuf == NULL) { 277 errno = ENOMEM; 278 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); 279 return (NULL); 280 } 281 anslen = res_nquery(pvt->res, qbuf, C_IN, T_PTR, ansbuf, MAXPACKET); 282 if (anslen < 0) { 283 memput(ansbuf, MAXPACKET); 284 return (NULL); 285 } 286 result = get1101mask(this, get1101answer(this, ansbuf, anslen, by_addr, 287 AF_INET, NULL, net, len)); 288 memput(ansbuf, MAXPACKET); 289 return (result); 290 } 291 292 static struct nwent * 293 get1101answer(struct irs_nw *this, 294 u_char *ansbuf, int anslen, enum by_what by_what, 295 int af, const char *name, const u_char *addr, int addrlen) 296 { 297 struct pvt *pvt = (struct pvt *)this->private; 298 int type, class, ancount, qdcount, haveanswer; 299 char *bp, *ep, **ap; 300 u_char *cp, *eom; 301 HEADER *hp; 302 303 /* Initialize, and parse header. */ 304 eom = ansbuf + anslen; 305 if (ansbuf + HFIXEDSZ > eom) { 306 RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); 307 return (NULL); 308 } 309 hp = (HEADER *)ansbuf; 310 cp = ansbuf + HFIXEDSZ; 311 qdcount = ntohs(hp->qdcount); 312 while (qdcount-- > 0) { 313 int n = dn_skipname(cp, eom); 314 cp += n + QFIXEDSZ; 315 if (n < 0 || cp > eom) { 316 RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); 317 return (NULL); 318 } 319 } 320 ancount = ntohs(hp->ancount); 321 if (!ancount) { 322 if (hp->aa) 323 RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND); 324 else 325 RES_SET_H_ERRNO(pvt->res, TRY_AGAIN); 326 return (NULL); 327 } 328 329 /* Prepare a return structure. */ 330 bp = pvt->buf; 331 ep = pvt->buf + sizeof(pvt->buf); 332 pvt->net.n_name = NULL; 333 pvt->net.n_aliases = pvt->ali; 334 pvt->net.n_addrtype = af; 335 pvt->net.n_addr = NULL; 336 pvt->net.n_length = addrlen; 337 338 /* Save input key if given. */ 339 switch (by_what) { 340 case by_name: 341 if (name != NULL) { 342 int n = strlen(name) + 1; 343 344 if (n > (ep - bp)) { 345 RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); 346 return (NULL); 347 } 348 pvt->net.n_name = strcpy(bp, name); /* (checked) */ 349 bp += n; 350 } 351 break; 352 case by_addr: 353 if (addr != NULL && addrlen != 0) { 354 int n = addrlen / 8 + ((addrlen % 8) != 0); 355 356 if (INADDRSZ > (ep - bp)) { 357 RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); 358 return (NULL); 359 } 360 memset(bp, 0, INADDRSZ); 361 memcpy(bp, addr, n); 362 pvt->net.n_addr = bp; 363 bp += INADDRSZ; 364 } 365 break; 366 default: 367 abort(); 368 } 369 370 /* Parse the answer, collect aliases. */ 371 ap = pvt->ali; 372 haveanswer = 0; 373 while (--ancount >= 0 && cp < eom) { 374 int n = dn_expand(ansbuf, eom, cp, bp, ep - bp); 375 376 cp += n; /*%< Owner */ 377 if (n < 0 || !maybe_dnok(pvt->res, bp) || 378 cp + 3 * INT16SZ + INT32SZ > eom) { 379 RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); 380 return (NULL); 381 } 382 GETSHORT(type, cp); /*%< Type */ 383 GETSHORT(class, cp); /*%< Class */ 384 cp += INT32SZ; /*%< TTL */ 385 GETSHORT(n, cp); /*%< RDLENGTH */ 386 if (class == C_IN && type == T_PTR) { 387 int nn; 388 389 nn = dn_expand(ansbuf, eom, cp, bp, ep - bp); 390 if (nn < 0 || !maybe_hnok(pvt->res, bp) || nn != n) { 391 RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); 392 return (NULL); 393 } 394 normalize_name(bp); 395 switch (by_what) { 396 case by_addr: { 397 if (pvt->net.n_name == NULL) 398 pvt->net.n_name = bp; 399 else if (ns_samename(pvt->net.n_name, bp) == 1) 400 break; 401 else 402 *ap++ = bp; 403 nn = strlen(bp) + 1; 404 bp += nn; 405 haveanswer++; 406 break; 407 } 408 case by_name: { 409 u_int b1, b2, b3, b4; 410 411 if (pvt->net.n_addr != NULL || 412 sscanf(bp, "%u.%u.%u.%u.in-addr.arpa", 413 &b1, &b2, &b3, &b4) != 4) 414 break; 415 if ((ep - bp) < INADDRSZ) { 416 RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); 417 return (NULL); 418 } 419 pvt->net.n_addr = bp; 420 *bp++ = b4; 421 *bp++ = b3; 422 *bp++ = b2; 423 *bp++ = b1; 424 pvt->net.n_length = INADDRSZ * 8; 425 haveanswer++; 426 } 427 } 428 } 429 cp += n; /*%< RDATA */ 430 } 431 if (!haveanswer) { 432 RES_SET_H_ERRNO(pvt->res, TRY_AGAIN); 433 return (NULL); 434 } 435 *ap = NULL; 436 437 return (&pvt->net); 438 } 439 440 static struct nwent * 441 get1101mask(struct irs_nw *this, struct nwent *nwent) { 442 struct pvt *pvt = (struct pvt *)this->private; 443 char qbuf[sizeof "255.255.255.255.in-addr.arpa"], owner[MAXDNAME]; 444 int anslen, type, class, ancount, qdcount; 445 u_char *ansbuf, *cp, *eom; 446 HEADER *hp; 447 448 if (!nwent) 449 return (NULL); 450 if (make1101inaddr(nwent->n_addr, nwent->n_length, qbuf, sizeof qbuf) 451 < 0) { 452 /* "First, do no harm." */ 453 return (nwent); 454 } 455 456 ansbuf = memget(MAXPACKET); 457 if (ansbuf == NULL) { 458 errno = ENOMEM; 459 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL); 460 return (NULL); 461 } 462 /* Query for the A RR that would hold this network's mask. */ 463 anslen = res_nquery(pvt->res, qbuf, C_IN, T_A, ansbuf, MAXPACKET); 464 if (anslen < HFIXEDSZ) { 465 memput(ansbuf, MAXPACKET); 466 return (nwent); 467 } 468 469 /* Initialize, and parse header. */ 470 hp = (HEADER *)ansbuf; 471 cp = ansbuf + HFIXEDSZ; 472 eom = ansbuf + anslen; 473 qdcount = ntohs(hp->qdcount); 474 while (qdcount-- > 0) { 475 int n = dn_skipname(cp, eom); 476 cp += n + QFIXEDSZ; 477 if (n < 0 || cp > eom) { 478 memput(ansbuf, MAXPACKET); 479 return (nwent); 480 } 481 } 482 ancount = ntohs(hp->ancount); 483 484 /* Parse the answer, collect aliases. */ 485 while (--ancount >= 0 && cp < eom) { 486 int n = dn_expand(ansbuf, eom, cp, owner, sizeof owner); 487 488 if (n < 0 || !maybe_dnok(pvt->res, owner)) 489 break; 490 cp += n; /*%< Owner */ 491 if (cp + 3 * INT16SZ + INT32SZ > eom) 492 break; 493 GETSHORT(type, cp); /*%< Type */ 494 GETSHORT(class, cp); /*%< Class */ 495 cp += INT32SZ; /*%< TTL */ 496 GETSHORT(n, cp); /*%< RDLENGTH */ 497 if (cp + n > eom) 498 break; 499 if (n == INADDRSZ && class == C_IN && type == T_A && 500 ns_samename(qbuf, owner) == 1) { 501 /* This A RR indicates the actual netmask. */ 502 int nn, mm; 503 504 nwent->n_length = 0; 505 for (nn = 0; nn < INADDRSZ; nn++) 506 for (mm = 7; mm >= 0; mm--) 507 if (cp[nn] & (1 << mm)) 508 nwent->n_length++; 509 else 510 break; 511 } 512 cp += n; /*%< RDATA */ 513 } 514 memput(ansbuf, MAXPACKET); 515 return (nwent); 516 } 517 518 static int 519 make1101inaddr(const u_char *net, int bits, char *name, int size) { 520 int n, m; 521 char *ep; 522 523 ep = name + size; 524 525 /* Zero fill any whole bytes left out of the prefix. */ 526 for (n = (32 - bits) / 8; n > 0; n--) { 527 if (ep - name < (int)(sizeof "0.")) 528 goto emsgsize; 529 m = SPRINTF((name, "0.")); 530 name += m; 531 } 532 533 /* Format the partial byte, if any, within the prefix. */ 534 if ((n = bits % 8) != 0) { 535 if (ep - name < (int)(sizeof "255.")) 536 goto emsgsize; 537 m = SPRINTF((name, "%u.", 538 net[bits / 8] & ~((1 << (8 - n)) - 1))); 539 name += m; 540 } 541 542 /* Format the whole bytes within the prefix. */ 543 for (n = bits / 8; n > 0; n--) { 544 if (ep - name < (int)(sizeof "255.")) 545 goto emsgsize; 546 m = SPRINTF((name, "%u.", net[n - 1])); 547 name += m; 548 } 549 550 /* Add the static text. */ 551 if (ep - name < (int)(sizeof "in-addr.arpa")) 552 goto emsgsize; 553 (void) SPRINTF((name, "in-addr.arpa")); 554 return (0); 555 556 emsgsize: 557 errno = EMSGSIZE; 558 return (-1); 559 } 560 561 static void 562 normalize_name(char *name) { 563 char *t; 564 565 /* Make lower case. */ 566 for (t = name; *t; t++) 567 if (isascii((unsigned char)*t) && isupper((unsigned char)*t)) 568 *t = tolower((*t)&0xff); 569 570 /* Remove trailing dots. */ 571 while (t > name && t[-1] == '.') 572 *--t = '\0'; 573 } 574 575 static int 576 init(struct irs_nw *this) { 577 struct pvt *pvt = (struct pvt *)this->private; 578 579 if (!pvt->res && !nw_res_get(this)) 580 return (-1); 581 if (((pvt->res->options & RES_INIT) == 0U) && 582 res_ninit(pvt->res) == -1) 583 return (-1); 584 return (0); 585 } 586 587 /*! \file */ 588