File:  [DragonFly] / src / lib / libc / net / res_query.c
Revision 1.2: download - view: text, annotated - select for diffs
Tue Jun 17 04:26:44 2003 UTC (11 years, 1 month ago) by dillon
Branches: MAIN
CVS tags: HEAD
Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids.  Most
ids have been removed from !lint sections and moved into comment sections.

    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:  * 3. All advertising materials mentioning features or use of this software
   14:  *    must display the following acknowledgement:
   15:  * 	This product includes software developed by the University of
   16:  * 	California, Berkeley and its contributors.
   17:  * 4. Neither the name of the University nor the names of its contributors
   18:  *    may be used to endorse or promote products derived from this software
   19:  *    without specific prior written permission.
   20:  * 
   21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31:  * SUCH DAMAGE.
   32:  *
   33:  * @(#)res_query.c	8.1 (Berkeley) 6/4/93
   34:  * $From: Id: res_query.c,v 8.14 1997/06/09 17:47:05 halley Exp $
   35:  * $FreeBSD: src/lib/libc/net/res_query.c,v 1.19.2.2 2002/07/07 11:34:42 robert Exp $
   36:  * $DragonFly: src/lib/libc/net/res_query.c,v 1.2 2003/06/17 04:26:44 dillon Exp $
   37:  */
   38: 
   39: /*
   40:  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
   41:  * 
   42:  * Permission to use, copy, modify, and distribute this software for any
   43:  * purpose with or without fee is hereby granted, provided that the above
   44:  * copyright notice and this permission notice appear in all copies, and that
   45:  * the name of Digital Equipment Corporation not be used in advertising or
   46:  * publicity pertaining to distribution of the document or software without
   47:  * specific, written prior permission.
   48:  * 
   49:  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
   50:  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
   51:  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
   52:  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
   53:  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
   54:  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
   55:  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
   56:  * SOFTWARE.
   57:  */
   58: 
   59: /*
   60:  * Portions Copyright (c) 1996 by Internet Software Consortium.
   61:  *
   62:  * Permission to use, copy, modify, and distribute this software for any
   63:  * purpose with or without fee is hereby granted, provided that the above
   64:  * copyright notice and this permission notice appear in all copies.
   65:  *
   66:  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
   67:  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
   68:  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
   69:  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
   70:  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
   71:  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
   72:  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
   73:  * SOFTWARE.
   74:  */
   75: 
   76: #include <sys/types.h>
   77: #include <sys/param.h>
   78: #include <netinet/in.h>
   79: #include <arpa/inet.h>
   80: #include <arpa/nameser.h>
   81: #include <ctype.h>
   82: #include <errno.h>
   83: #include <netdb.h>
   84: #include <resolv.h>
   85: #include <stdio.h>
   86: #include <stdlib.h>
   87: #include <string.h>
   88: 
   89: #include "res_config.h"
   90: 
   91: #if PACKETSZ > 1024
   92: #define MAXPACKET	PACKETSZ
   93: #else
   94: #define MAXPACKET	1024
   95: #endif
   96: 
   97: /*
   98:  * Formulate a normal query, send, and await answer.
   99:  * Returned answer is placed in supplied buffer "answer".
  100:  * Perform preliminary check of answer, returning success only
  101:  * if no error is indicated and the answer count is nonzero.
  102:  * Return the size of the response on success, -1 on error.
  103:  * Error number is left in h_errno.
  104:  *
  105:  * Caller must parse answer and determine whether it answers the question.
  106:  */
  107: int
  108: res_query(name, class, type, answer, anslen)
  109: 	const char *name;	/* domain name */
  110: 	int class, type;	/* class and type of query */
  111: 	u_char *answer;		/* buffer to put answer */
  112: 	int anslen;		/* size of answer buffer */
  113: {
  114: 	u_char buf[MAXPACKET];
  115: 	HEADER *hp = (HEADER *) answer;
  116: 	int n;
  117: 
  118: 	hp->rcode = NOERROR;	/* default */
  119: 
  120: 	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
  121: 		h_errno = NETDB_INTERNAL;
  122: 		return (-1);
  123: 	}
  124: #ifdef DEBUG
  125: 	if (_res.options & RES_DEBUG)
  126: 		printf(";; res_query(%s, %d, %d)\n", name, class, type);
  127: #endif
  128: 
  129: 	n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL,
  130: 			buf, sizeof(buf));
  131: 	if (n > 0 && (_res.options & RES_USE_EDNS0) != 0)
  132: 		n = res_opt(n, buf, sizeof(buf), anslen);
  133: 	if (n <= 0) {
  134: #ifdef DEBUG
  135: 		if (_res.options & RES_DEBUG)
  136: 			printf(";; res_query: mkquery failed\n");
  137: #endif
  138: 		h_errno = NO_RECOVERY;
  139: 		return (n);
  140: 	}
  141: 	n = res_send(buf, n, answer, anslen);
  142: 	if (n < 0) {
  143: #ifdef DEBUG
  144: 		if (_res.options & RES_DEBUG)
  145: 			printf(";; res_query: send error\n");
  146: #endif
  147: 		h_errno = TRY_AGAIN;
  148: 		return (n);
  149: 	}
  150: 
  151: 	if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
  152: #ifdef DEBUG
  153: 		if (_res.options & RES_DEBUG)
  154: 			printf(";; rcode = %d, ancount=%d\n", hp->rcode,
  155: 			    ntohs(hp->ancount));
  156: #endif
  157: 		switch (hp->rcode) {
  158: 		case NXDOMAIN:
  159: 			h_errno = HOST_NOT_FOUND;
  160: 			break;
  161: 		case SERVFAIL:
  162: 			h_errno = TRY_AGAIN;
  163: 			break;
  164: 		case NOERROR:
  165: 			h_errno = NO_DATA;
  166: 			break;
  167: 		case FORMERR:
  168: 		case NOTIMP:
  169: 		case REFUSED:
  170: 		default:
  171: 			h_errno = NO_RECOVERY;
  172: 			break;
  173: 		}
  174: 		return (-1);
  175: 	}
  176: 	return (n);
  177: }
  178: 
  179: /*
  180:  * Formulate a normal query, send, and retrieve answer in supplied buffer.
  181:  * Return the size of the response on success, -1 on error.
  182:  * If enabled, implement search rules until answer or unrecoverable failure
  183:  * is detected.  Error code, if any, is left in h_errno.
  184:  */
  185: int
  186: res_search(name, class, type, answer, anslen)
  187: 	const char *name;	/* domain name */
  188: 	int class, type;	/* class and type of query */
  189: 	u_char *answer;		/* buffer to put answer */
  190: 	int anslen;		/* size of answer */
  191: {
  192: 	const char *cp, * const *domain;
  193: 	HEADER *hp = (HEADER *) answer;
  194: 	u_int dots;
  195: 	int trailing_dot, ret, saved_herrno;
  196: 	int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
  197: 
  198: 	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
  199: 		h_errno = NETDB_INTERNAL;
  200: 		return (-1);
  201: 	}
  202: 	errno = 0;
  203: 	h_errno = HOST_NOT_FOUND;	/* default, if we never query */
  204: 	dots = 0;
  205: 	for (cp = name; *cp; cp++)
  206: 		dots += (*cp == '.');
  207: 	trailing_dot = 0;
  208: 	if (cp > name && *--cp == '.')
  209: 		trailing_dot++;
  210: 
  211: 	/* If there aren't any dots, it could be a user-level alias */
  212: 	if (!dots && (cp = hostalias(name)) != NULL)
  213: 		return (res_query(cp, class, type, answer, anslen));
  214: 
  215: 	/*
  216: 	 * If there are dots in the name already, let's just give it a try
  217: 	 * 'as is'.  The threshold can be set with the "ndots" option.
  218: 	 */
  219: 	saved_herrno = -1;
  220: 	if (dots >= _res.ndots) {
  221: 		ret = res_querydomain(name, NULL, class, type, answer, anslen);
  222: 		if (ret > 0)
  223: 			return (ret);
  224: 		saved_herrno = h_errno;
  225: 		tried_as_is++;
  226: 	}
  227: 
  228: 	/*
  229: 	 * We do at least one level of search if
  230: 	 *	- there is no dot and RES_DEFNAME is set, or
  231: 	 *	- there is at least one dot, there is no trailing dot,
  232: 	 *	  and RES_DNSRCH is set.
  233: 	 */
  234: 	if ((!dots && (_res.options & RES_DEFNAMES)) ||
  235: 	    (dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
  236: 		int done = 0;
  237: 
  238: 		for (domain = (const char * const *)_res.dnsrch;
  239: 		     *domain && !done;
  240: 		     domain++) {
  241: 
  242: 			ret = res_querydomain(name, *domain, class, type,
  243: 					      answer, anslen);
  244: 			if (ret > 0)
  245: 				return (ret);
  246: 
  247: 			/*
  248: 			 * If no server present, give up.
  249: 			 * If name isn't found in this domain,
  250: 			 * keep trying higher domains in the search list
  251: 			 * (if that's enabled).
  252: 			 * On a NO_DATA error, keep trying, otherwise
  253: 			 * a wildcard entry of another type could keep us
  254: 			 * from finding this entry higher in the domain.
  255: 			 * If we get some other error (negative answer or
  256: 			 * server failure), then stop searching up,
  257: 			 * but try the input name below in case it's
  258: 			 * fully-qualified.
  259: 			 */
  260: 			if (errno == ECONNREFUSED) {
  261: 				h_errno = TRY_AGAIN;
  262: 				return (-1);
  263: 			}
  264: 
  265: 			switch (h_errno) {
  266: 			case NO_DATA:
  267: 				got_nodata++;
  268: 				/* FALLTHROUGH */
  269: 			case HOST_NOT_FOUND:
  270: 				/* keep trying */
  271: 				break;
  272: 			case TRY_AGAIN:
  273: 				if (hp->rcode == SERVFAIL) {
  274: 					/* try next search element, if any */
  275: 					got_servfail++;
  276: 					break;
  277: 				}
  278: 				/* FALLTHROUGH */
  279: 			default:
  280: 				/* anything else implies that we're done */
  281: 				done++;
  282: 			}
  283: 
  284: 			/* if we got here for some reason other than DNSRCH,
  285: 			 * we only wanted one iteration of the loop, so stop.
  286: 			 */
  287: 			if (!(_res.options & RES_DNSRCH))
  288: 				done++;
  289: 		}
  290: 	}
  291: 
  292: 	/*
  293: 	 * If we have not already tried the name "as is", do that now.
  294: 	 * note that we do this regardless of how many dots were in the
  295: 	 * name or whether it ends with a dot unless NOTLDQUERY is set.
  296: 	 */
  297: 	if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) {
  298: 		ret = res_querydomain(name, NULL, class, type, answer, anslen);
  299: 		if (ret > 0)
  300: 			return (ret);
  301: 	}
  302: 
  303: 	/* if we got here, we didn't satisfy the search.
  304: 	 * if we did an initial full query, return that query's h_errno
  305: 	 * (note that we wouldn't be here if that query had succeeded).
  306: 	 * else if we ever got a nodata, send that back as the reason.
  307: 	 * else send back meaningless h_errno, that being the one from
  308: 	 * the last DNSRCH we did.
  309: 	 */
  310: 	if (saved_herrno != -1)
  311: 		h_errno = saved_herrno;
  312: 	else if (got_nodata)
  313: 		h_errno = NO_DATA;
  314: 	else if (got_servfail)
  315: 		h_errno = TRY_AGAIN;
  316: 	return (-1);
  317: }
  318: 
  319: /*
  320:  * Perform a call on res_query on the concatenation of name and domain,
  321:  * removing a trailing dot from name if domain is NULL.
  322:  */
  323: int
  324: res_querydomain(name, domain, class, type, answer, anslen)
  325: 	const char *name, *domain;
  326: 	int class, type;	/* class and type of query */
  327: 	u_char *answer;		/* buffer to put answer */
  328: 	int anslen;		/* size of answer */
  329: {
  330: 	char nbuf[MAXDNAME];
  331: 	const char *longname = nbuf;
  332: 	int n, d;
  333: 
  334: 	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
  335: 		h_errno = NETDB_INTERNAL;
  336: 		return (-1);
  337: 	}
  338: #ifdef DEBUG
  339: 	if (_res.options & RES_DEBUG)
  340: 		printf(";; res_querydomain(%s, %s, %d, %d)\n",
  341: 		       name, domain?domain:"<Nil>", class, type);
  342: #endif
  343: 	if (domain == NULL) {
  344: 		/*
  345: 		 * Check for trailing '.';
  346: 		 * copy without '.' if present.
  347: 		 */
  348: 		n = strlen(name);
  349: 		if (n >= MAXDNAME) {
  350: 			h_errno = NO_RECOVERY;
  351: 			return (-1);
  352: 		}
  353: 		n--;
  354: 		if (n >= 0 && name[n] == '.') {
  355: 			strncpy(nbuf, name, n);
  356: 			nbuf[n] = '\0';
  357: 		} else
  358: 			longname = name;
  359: 	} else {
  360: 		n = strlen(name);
  361: 		d = strlen(domain);
  362: 		if (n + d + 1 >= MAXDNAME) {
  363: 			h_errno = NO_RECOVERY;
  364: 			return (-1);
  365: 		}
  366: 		sprintf(nbuf, "%s.%s", name, domain);
  367: 	}
  368: 	return (res_query(longname, class, type, answer, anslen));
  369: }
  370: 
  371: const char *
  372: hostalias(name)
  373: 	const char *name;
  374: {
  375: 	register char *cp1, *cp2;
  376: 	FILE *fp;
  377: 	char *file;
  378: 	char buf[BUFSIZ];
  379: 	static char abuf[MAXDNAME];
  380: 
  381: 	if (_res.options & RES_NOALIASES)
  382: 		return (NULL);
  383: 	if (issetugid())
  384: 		return (NULL);
  385: 	file = getenv("HOSTALIASES");
  386: 	if (file == NULL || (fp = fopen(file, "r")) == NULL)
  387: 		return (NULL);
  388: 	setbuf(fp, NULL);
  389: 	buf[sizeof(buf) - 1] = '\0';
  390: 	while (fgets(buf, sizeof(buf), fp)) {
  391: 		for (cp1 = buf; *cp1 && !isspace((unsigned char)*cp1); ++cp1)
  392: 			;
  393: 		if (!*cp1)
  394: 			break;
  395: 		*cp1 = '\0';
  396: 		if (!strcasecmp(buf, name)) {
  397: 			while (isspace((unsigned char)*++cp1))
  398: 				;
  399: 			if (!*cp1)
  400: 				break;
  401: 			for (cp2 = cp1 + 1; *cp2 && !isspace((unsigned char)*cp2); ++cp2)
  402: 				;
  403: 			abuf[sizeof(abuf) - 1] = *cp2 = '\0';
  404: 			strncpy(abuf, cp1, sizeof(abuf) - 1);
  405: 			fclose(fp);
  406: 			return (abuf);
  407: 		}
  408: 	}
  409: 	fclose(fp);
  410: 	return (NULL);
  411: }
  412: 
  413: /*
  414:  * Weak aliases for applications that use certain private entry points,
  415:  * and fail to include <resolv.h>.
  416:  */
  417: #undef res_query
  418: __weak_reference(__res_query, res_query);
  419: #undef res_search
  420: __weak_reference(__res_search, res_search);
  421: #undef res_querydomain
  422: __weak_reference(__res_querydomain, res_querydomain);