(linenum→info "unix/slp.c:2238")

glibc/2.7/resolv/res_query.c

    1: /*
    2:  * Copyright (c) 1988, 1993
    3:  *    The Regents of the University of California.  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:  * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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: /*
   31:  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
   32:  *
   33:  * Permission to use, copy, modify, and distribute this software for any
   34:  * purpose with or without fee is hereby granted, provided that the above
   35:  * copyright notice and this permission notice appear in all copies, and that
   36:  * the name of Digital Equipment Corporation not be used in advertising or
   37:  * publicity pertaining to distribution of the document or software without
   38:  * specific, written prior permission.
   39:  *
   40:  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
   41:  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
   42:  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
   43:  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
   44:  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
   45:  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
   46:  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
   47:  * SOFTWARE.
   48:  */
   49: 
   50: /*
   51:  * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
   52:  *
   53:  * Permission to use, copy, modify, and distribute this software for any
   54:  * purpose with or without fee is hereby granted, provided that the above
   55:  * copyright notice and this permission notice appear in all copies.
   56:  *
   57:  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
   58:  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
   59:  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
   60:  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
   61:  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
   62:  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
   63:  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
   64:  * SOFTWARE.
   65:  */
   66: 
   67: #if defined(LIBC_SCCS) && !defined(lint)
   68: static const char sccsid[] = "@(#)res_query.c   8.1 (Berkeley) 6/4/93";
   69: static const char rcsid[] = "$BINDId: res_query.c,v 8.20 2000/02/29 05:39:12 vixie Exp $";
   70: #endif /* LIBC_SCCS and not lint */
   71: 
   72: #include <assert.h>
   73: #include <sys/types.h>
   74: #include <sys/param.h>
   75: #include <netinet/in.h>
   76: #include <arpa/inet.h>
   77: #include <arpa/nameser.h>
   78: #include <ctype.h>
   79: #include <errno.h>
   80: #include <netdb.h>
   81: #include <resolv.h>
   82: #include <stdio.h>
   83: #include <stdlib.h>
   84: #include <string.h>
   85: 
   86: /* Options.  Leave them on. */
   87: /* #undef DEBUG */
   88: 
   89: #if PACKETSZ > 65536
   90: #define MAXPACKET       PACKETSZ
   91: #else
   92: #define MAXPACKET       65536
   93: #endif
   94: 
   95: #define QUERYSIZE       (HFIXEDSZ + QFIXEDSZ + MAXCDNAME + 1)
   96: 
   97: static int
   98: __libc_res_nquerydomain(res_state statp, const char *name, const char *domain,
   99:                         int class, int type, u_char *answer, int anslen,
  100:                         u_char **answerp);
  101: 
  102: /*
  103:  * Formulate a normal query, send, and await answer.
  104:  * Returned answer is placed in supplied buffer "answer".
  105:  * Perform preliminary check of answer, returning success only
  106:  * if no error is indicated and the answer count is nonzero.
  107:  * Return the size of the response on success, -1 on error.
  108:  * Error number is left in H_ERRNO.
  109:  *
  110:  * Caller must parse answer and determine whether it answers the question.
  111:  */
  112: int
  113: __libc_res_nquery(res_state statp,
  114:                   const char *name,   /* domain name */
  115:                   int class, int type,        /* class and type of query */
  116:                   u_char *answer,     /* buffer to put answer */
  117:                   int anslen,         /* size of answer buffer */
  118:                   u_char **answerp)   /* if buffer needs to be enlarged */
  119: {
  120:         u_char *buf;
  121:         HEADER *hp = (HEADER *) answer;
  122:         int n, use_malloc = 0;
  123:         u_int oflags = statp->_flags;
  124: 
  125:         size_t bufsize = QUERYSIZE;
  126:         buf = alloca (bufsize);
  127: 
  128:  again:
  129:         hp->rcode = NOERROR;   /* default */
  130: 
  131: #ifdef DEBUG
  132:         if (statp->options & RES_DEBUG)
  133:                 printf(";; res_query(%s, %d, %d)\n", name, class, type);
  134: #endif
  135: 
  136:         n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
  137:                          buf, bufsize);
  138:         if (n > 0
  139:             && (oflags & RES_F_EDNS0ERR) == 0
  140:             && (statp->options & RES_USE_EDNS0) != 0)
  141:                 n = __res_nopt(statp, n, buf, bufsize, anslen);
  142:         if (__builtin_expect (n <= 0, 0) && !use_malloc) {
  143:                 /* Retry just in case res_nmkquery failed because of too
  144:                    short buffer.  Shouldn't happen.  */
  145:                 bufsize = MAXPACKET;
  146:                 buf = malloc (bufsize);
  147:                 if (buf != NULL) {
  148:                         use_malloc = 1;
  149:                         goto again;
  150:                 }
  151:         }
  152:         if (__builtin_expect (n <= 0, 0)) {
  153:                 /* If the query choked with EDNS0, retry without EDNS0.  */
  154:                 if ((statp->options & RES_USE_EDNS0) != 0
  155:                     && ((oflags ^ statp->_flags) & RES_F_EDNS0ERR) != 0) {
  156:                         statp->_flags |= RES_F_EDNS0ERR;
  157:                         if (statp->options & RES_DEBUG)
  158:                                 printf(";; res_nquery: retry without EDNS0\n");
  159:                         goto again;
  160:                 }
  161: #ifdef DEBUG
  162:                 if (statp->options & RES_DEBUG)
  163:                         printf(";; res_query: mkquery failed\n");
  164: #endif
  165:                 RES_SET_H_ERRNO(statp, NO_RECOVERY);
  166:                 if (use_malloc)
  167:                         free (buf);
  168:                 return (n);
  169:         }
  170:         assert (answerp == NULL || (void *) *answerp == (void *) answer);
  171:         n = __libc_res_nsend(statp, buf, n, answer, anslen, answerp);
  172:         if (use_malloc)
  173:                 free (buf);
  174:         if (n < 0) {
  175: #ifdef DEBUG
  176:                 if (statp->options & RES_DEBUG)
  177:                         printf(";; res_query: send error\n");
  178: #endif
  179:                 RES_SET_H_ERRNO(statp, TRY_AGAIN);
  180:                 return (n);
  181:         }
  182: 
  183:         if (answerp != NULL)
  184:           /* __libc_res_nsend might have reallocated the buffer.  */
  185:           hp = (HEADER *) *answerp;
  186: 
  187:         if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
  188: #ifdef DEBUG
  189:                 if (statp->options & RES_DEBUG)
  190:                         printf(";; rcode = %d, ancount=%d\n", hp->rcode,
  191:                             ntohs(hp->ancount));
  192: #endif
  193:                 switch (hp->rcode) {
  194:                 case NXDOMAIN:
  195:                         RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
  196:                         break;
  197:                 case SERVFAIL:
  198:                         RES_SET_H_ERRNO(statp, TRY_AGAIN);
  199:                         break;
  200:                 case NOERROR:
  201:                         RES_SET_H_ERRNO(statp, NO_DATA);
  202:                         break;
  203:                 case FORMERR:
  204:                 case NOTIMP:
  205:                 case REFUSED:
  206:                 default:
  207:                         RES_SET_H_ERRNO(statp, NO_RECOVERY);
  208:                         break;
  209:                 }
  210:                 return (-1);
  211:         }
  212:         return (n);
  213: }
  214: libresolv_hidden_def (__libc_res_nquery)
  215: 
  216: int
  217: res_nquery(res_state statp,
  218:            const char *name,   /* domain name */
  219:            int class, int type,        /* class and type of query */
  220:            u_char *answer,     /* buffer to put answer */
  221:            int anslen)         /* size of answer buffer */
  222: {
  223:         return __libc_res_nquery(statp, name, class, type, answer, anslen,
  224:                                  NULL);
  225: }
  226: libresolv_hidden_def (res_nquery)
  227: 
  228: /*
  229:  * Formulate a normal query, send, and retrieve answer in supplied buffer.
  230:  * Return the size of the response on success, -1 on error.
  231:  * If enabled, implement search rules until answer or unrecoverable failure
  232:  * is detected.  Error code, if any, is left in H_ERRNO.
  233:  */
  234: int
  235: __libc_res_nsearch(res_state statp,
  236:             const char *name,  /* domain name */
  237:             int class, int type,       /* class and type of query */
  238:             u_char *answer,    /* buffer to put answer */
  239:             int anslen,                /* size of answer */
  240:             u_char **answerp)
  241: {
  242:         const char *cp, * const *domain;
  243:         HEADER *hp = (HEADER *) answer;
  244:         char tmp[NS_MAXDNAME];
  245:         u_int dots;
  246:         int trailing_dot, ret, saved_herrno;
  247:         int got_nodata = 0, got_servfail = 0, root_on_list = 0;
  248:         int tried_as_is = 0;
  249: 
  250:         __set_errno (0);
  251:         RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);  /* True if we never query. */
  252: 
  253:         dots = 0;
  254:         for (cp = name; *cp != '\0'; cp++)
  255:                 dots += (*cp == '.');
  256:         trailing_dot = 0;
  257:         if (cp > name && *--cp == '.')
  258:                 trailing_dot++;
  259: 
  260:         /* If there aren't any dots, it could be a user-level alias. */
  261:         if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
  262:                 return (__libc_res_nquery(statp, cp, class, type, answer,
  263:                                           anslen, answerp));
  264: 
  265: #ifdef DEBUG
  266:         if (statp->options & RES_DEBUG)
  267:                 printf("dots=%d, statp->ndots=%d, trailing_dot=%d, name=%s\n",
  268:                        (int)dots,(int)statp->ndots,(int)trailing_dot,name);
  269: #endif
  270: 
  271:         /*
  272:          * If there are enough dots in the name, let's just give it a
  273:          * try 'as is'. The threshold can be set with the "ndots" option.
  274:          * Also, query 'as is', if there is a trailing dot in the name.
  275:          */
  276:         saved_herrno = -1;
  277:         if (dots >= statp->ndots || trailing_dot) {
  278:                 ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
  279:                                               answer, anslen, answerp);
  280:                 if (ret > 0 || trailing_dot)
  281:                         return (ret);
  282:                 saved_herrno = h_errno;
  283:                 tried_as_is++;
  284:                 if (answerp && *answerp != answer) {
  285:                         answer = *answerp;
  286:                         anslen = MAXPACKET;
  287:                 }
  288:         }
  289: 
  290:         /*
  291:          * We do at least one level of search if
  292:          *     - there is no dot and RES_DEFNAME is set, or
  293:          *     - there is at least one dot, there is no trailing dot,
  294:          *       and RES_DNSRCH is set.
  295:          */
  296:         if ((!dots && (statp->options & RES_DEFNAMES) != 0) ||
  297:             (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0)) {
  298:                 int done = 0;
  299: 
  300:                 for (domain = (const char * const *)statp->dnsrch;
  301:                      *domain && !done;
  302:                      domain++) {
  303: 
  304:                         if (domain[0][0] == '\0' ||
  305:                             (domain[0][0] == '.' && domain[0][1] == '\0'))
  306:                                 root_on_list++;
  307: 
  308:                         ret = __libc_res_nquerydomain(statp, name, *domain,
  309:                                                       class, type,
  310:                                                       answer, anslen, answerp);
  311:                         if (ret > 0)
  312:                                 return (ret);
  313: 
  314:                         if (answerp && *answerp != answer) {
  315:                                 answer = *answerp;
  316:                                 anslen = MAXPACKET;
  317:                         }
  318: 
  319:                         /*
  320:                          * If no server present, give up.
  321:                          * If name isn't found in this domain,
  322:                          * keep trying higher domains in the search list
  323:                          * (if that's enabled).
  324:                          * On a NO_DATA error, keep trying, otherwise
  325:                          * a wildcard entry of another type could keep us
  326:                          * from finding this entry higher in the domain.
  327:                          * If we get some other error (negative answer or
  328:                          * server failure), then stop searching up,
  329:                          * but try the input name below in case it's
  330:                          * fully-qualified.
  331:                          */
  332:                         if (errno == ECONNREFUSED) {
  333:                                 RES_SET_H_ERRNO(statp, TRY_AGAIN);
  334:                                 return (-1);
  335:                         }
  336: 
  337:                         switch (statp->res_h_errno) {
  338:                         case NO_DATA:
  339:                                 got_nodata++;
  340:                                 /* FALLTHROUGH */
  341:                         case HOST_NOT_FOUND:
  342:                                 /* keep trying */
  343:                                 break;
  344:                         case TRY_AGAIN:
  345:                                 if (hp->rcode == SERVFAIL) {
  346:                                         /* try next search element, if any */
  347:                                         got_servfail++;
  348:                                         break;
  349:                                 }
  350:                                 /* FALLTHROUGH */
  351:                         default:
  352:                                 /* anything else implies that we're done */
  353:                                 done++;
  354:                         }
  355: 
  356:                         /* if we got here for some reason other than DNSRCH,
  357:                          * we only wanted one iteration of the loop, so stop.
  358:                          */
  359:                         if ((statp->options & RES_DNSRCH) == 0)
  360:                                 done++;
  361:                 }
  362:         }
  363: 
  364:         /*
  365:          * If the name has any dots at all, and no earlier 'as-is' query
  366:          * for the name, and "." is not on the search list, then try an as-is
  367:          * query now.
  368:          */
  369:         if (dots && !(tried_as_is || root_on_list)) {
  370:                 ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
  371:                                               answer, anslen, answerp);
  372:                 if (ret > 0)
  373:                         return (ret);
  374:         }
  375: 
  376:         /* if we got here, we didn't satisfy the search.
  377:          * if we did an initial full query, return that query's H_ERRNO
  378:          * (note that we wouldn't be here if that query had succeeded).
  379:          * else if we ever got a nodata, send that back as the reason.
  380:          * else send back meaningless H_ERRNO, that being the one from
  381:          * the last DNSRCH we did.
  382:          */
  383:         if (saved_herrno != -1)
  384:                 RES_SET_H_ERRNO(statp, saved_herrno);
  385:         else if (got_nodata)
  386:                 RES_SET_H_ERRNO(statp, NO_DATA);
  387:         else if (got_servfail)
  388:                 RES_SET_H_ERRNO(statp, TRY_AGAIN);
  389:         return (-1);
  390: }
  391: libresolv_hidden_def (__libc_res_nsearch)
  392: 
  393: int
  394: res_nsearch(res_state statp,
  395:             const char *name,  /* domain name */
  396:             int class, int type,       /* class and type of query */
  397:             u_char *answer,    /* buffer to put answer */
  398:             int anslen)                /* size of answer */
  399: {
  400:         return __libc_res_nsearch(statp, name, class, type, answer,
  401:                                   anslen, NULL);
  402: }
  403: libresolv_hidden_def (res_nsearch)
  404: 
  405: /*
  406:  * Perform a call on res_query on the concatenation of name and domain,
  407:  * removing a trailing dot from name if domain is NULL.
  408:  */
  409: static int
  410: __libc_res_nquerydomain(res_state statp,
  411:             const char *name,
  412:             const char *domain,
  413:             int class, int type,       /* class and type of query */
  414:             u_char *answer,            /* buffer to put answer */
  415:             int anslen,                        /* size of answer */
  416:             u_char **answerp)
  417: {
  418:         char nbuf[MAXDNAME];
  419:         const char *longname = nbuf;
  420:         int n, d;
  421: 
  422: #ifdef DEBUG
  423:         if (statp->options & RES_DEBUG)
  424:                 printf(";; res_nquerydomain(%s, %s, %d, %d)\n",
  425:                        name, domain?domain:"<Nil>", class, type);
  426: #endif
  427:         if (domain == NULL) {
  428:                 /*
  429:                  * Check for trailing '.';
  430:                  * copy without '.' if present.
  431:                  */
  432:                 n = strlen(name);
  433:                 if (n >= MAXDNAME) {
  434:                         RES_SET_H_ERRNO(statp, NO_RECOVERY);
  435:                         return (-1);
  436:                 }
  437:                 n--;
  438:                 if (n >= 0 && name[n] == '.') {
  439:                         strncpy(nbuf, name, n);
  440:                         nbuf[n] = '\0';
  441:                 } else
  442:                         longname = name;
  443:         } else {
  444:                 n = strlen(name);
  445:                 d = strlen(domain);
  446:                 if (n + d + 1 >= MAXDNAME) {
  447:                         RES_SET_H_ERRNO(statp, NO_RECOVERY);
  448:                         return (-1);
  449:                 }
  450:                 sprintf(nbuf, "%s.%s", name, domain);
  451:         }
  452:         return (__libc_res_nquery(statp, longname, class, type, answer,
  453:                                   anslen, answerp));
  454: }
  455: 
  456: int
  457: res_nquerydomain(res_state statp,
  458:             const char *name,
  459:             const char *domain,
  460:             int class, int type,       /* class and type of query */
  461:             u_char *answer,            /* buffer to put answer */
  462:             int anslen)                /* size of answer */
  463: {
  464:         return __libc_res_nquerydomain(statp, name, domain, class, type,
  465:                                        answer, anslen, NULL);
  466: }
  467: libresolv_hidden_def (res_nquerydomain)
  468: 
  469: const char *
  470: res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) {
  471:         char *file, *cp1, *cp2;
  472:         char buf[BUFSIZ];
  473:         FILE *fp;
  474: 
  475:         if (statp->options & RES_NOALIASES)
  476:                 return (NULL);
  477:         file = getenv("HOSTALIASES");
  478:         if (file == NULL || (fp = fopen(file, "r")) == NULL)
  479:                 return (NULL);
  480:         setbuf(fp, NULL);
  481:         buf[sizeof(buf) - 1] = '\0';
  482:         while (fgets(buf, sizeof(buf), fp)) {
  483:                 for (cp1 = buf; *cp1 && !isspace(*cp1); ++cp1)
  484:                         ;
  485:                 if (!*cp1)
  486:                         break;
  487:                 *cp1 = '\0';
  488:                 if (ns_samename(buf, name) == 1) {
  489:                         while (isspace(*++cp1))
  490:                                 ;
  491:                         if (!*cp1)
  492:                                 break;
  493:                         for (cp2 = cp1 + 1; *cp2 && !isspace(*cp2); ++cp2)
  494:                                 ;
  495:                         *cp2 = '\0';
  496:                         strncpy(dst, cp1, siz - 1);
  497:                         dst[siz - 1] = '\0';
  498:                         fclose(fp);
  499:                         return (dst);
  500:                 }
  501:         }
  502:         fclose(fp);
  503:         return (NULL);
  504: }
  505: libresolv_hidden_def (res_hostalias)
1
Syntax (Markdown)