diff options
author | rgrimes <rgrimes@FreeBSD.org> | 1994-05-27 05:00:24 +0000 |
---|---|---|
committer | rgrimes <rgrimes@FreeBSD.org> | 1994-05-27 05:00:24 +0000 |
commit | 8b1c40bc18615379af063dfafe0085ffa594da60 (patch) | |
tree | 643fba97374ab4016af248765b105611ab69f6d6 /lib/libc/net/res_query.c | |
download | FreeBSD-src-8b1c40bc18615379af063dfafe0085ffa594da60.zip FreeBSD-src-8b1c40bc18615379af063dfafe0085ffa594da60.tar.gz |
BSD 4.4 Lite Lib Sources
Diffstat (limited to 'lib/libc/net/res_query.c')
-rw-r--r-- | lib/libc/net/res_query.c | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/lib/libc/net/res_query.c b/lib/libc/net/res_query.c new file mode 100644 index 0000000..4980af1 --- /dev/null +++ b/lib/libc/net/res_query.c @@ -0,0 +1,303 @@ +/*- + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93"; +static char rcsid[] = "$Id: res_query.c,v 1.1 1993/06/01 09:42:14 vixie Exp vixie $"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> +#include <netdb.h> +#include <resolv.h> +#include <stdio.h> +#include <ctype.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#if PACKETSZ > 1024 +#define MAXPACKET PACKETSZ +#else +#define MAXPACKET 1024 +#endif + +int h_errno; + +/* + * Formulate a normal query, send, and await answer. + * Returned answer is placed in supplied buffer "answer". + * Perform preliminary check of answer, returning success only + * if no error is indicated and the answer count is nonzero. + * Return the size of the response on success, -1 on error. + * Error number is left in h_errno. + * Caller must parse answer and determine whether it answers the question. + */ +res_query(name, class, type, answer, anslen) + char *name; /* domain name */ + int class, type; /* class and type of query */ + u_char *answer; /* buffer to put answer */ + int anslen; /* size of answer buffer */ +{ + char buf[MAXPACKET]; + HEADER *hp; + int n; + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) + return (-1); +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf(";; res_query(%s, %d, %d)\n", name, class, type); +#endif + n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0, NULL, + buf, sizeof(buf)); + + if (n <= 0) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf(";; res_query: mkquery failed\n"); +#endif + h_errno = NO_RECOVERY; + return (n); + } + n = res_send(buf, n, (char *)answer, anslen); + if (n < 0) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf(";; res_query: send error\n"); +#endif + h_errno = TRY_AGAIN; + return(n); + } + + hp = (HEADER *) answer; + if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf(";; rcode = %d, ancount=%d\n", hp->rcode, + ntohs(hp->ancount)); +#endif + switch (hp->rcode) { + case NXDOMAIN: + h_errno = HOST_NOT_FOUND; + break; + case SERVFAIL: + h_errno = TRY_AGAIN; + break; + case NOERROR: + h_errno = NO_DATA; + break; + case FORMERR: + case NOTIMP: + case REFUSED: + default: + h_errno = NO_RECOVERY; + break; + } + return (-1); + } + return(n); +} + +/* + * Formulate a normal query, send, and retrieve answer in supplied buffer. + * Return the size of the response on success, -1 on error. + * If enabled, implement search rules until answer or unrecoverable failure + * is detected. Error number is left in h_errno. + * Only useful for queries in the same name hierarchy as the local host + * (not, for example, for host address-to-name lookups in domain in-addr.arpa). + */ +int +res_search(name, class, type, answer, anslen) + char *name; /* domain name */ + int class, type; /* class and type of query */ + u_char *answer; /* buffer to put answer */ + int anslen; /* size of answer */ +{ + register char *cp, **domain; + int n, ret, got_nodata = 0; + char *__hostalias(); + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) + return (-1); + + errno = 0; + h_errno = HOST_NOT_FOUND; /* default, if we never query */ + for (cp = name, n = 0; *cp; cp++) + if (*cp == '.') + n++; + if (n == 0 && (cp = __hostalias(name))) + return (res_query(cp, class, type, answer, anslen)); + + /* + * We do at least one level of search if + * - there is no dot and RES_DEFNAME is set, or + * - there is at least one dot, there is no trailing dot, + * and RES_DNSRCH is set. + */ + if ((n == 0 && _res.options & RES_DEFNAMES) || + (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH)) + for (domain = _res.dnsrch; *domain; domain++) { + ret = res_querydomain(name, *domain, class, type, + answer, anslen); + if (ret > 0) + return (ret); + /* + * If no server present, give up. + * If name isn't found in this domain, + * keep trying higher domains in the search list + * (if that's enabled). + * On a NO_DATA error, keep trying, otherwise + * a wildcard entry of another type could keep us + * from finding this entry higher in the domain. + * If we get some other error (negative answer or + * server failure), then stop searching up, + * but try the input name below in case it's fully-qualified. + */ + if (errno == ECONNREFUSED) { + h_errno = TRY_AGAIN; + return (-1); + } + if (h_errno == NO_DATA) + got_nodata++; + if ((h_errno != HOST_NOT_FOUND && h_errno != NO_DATA) || + (_res.options & RES_DNSRCH) == 0) + break; + } + /* + * If the search/default failed, try the name as fully-qualified, + * but only if it contained at least one dot (even trailing). + * This is purely a heuristic; we assume that any reasonable query + * about a top-level domain (for servers, SOA, etc) will not use + * res_search. + */ + if (n && (ret = res_querydomain(name, (char *)NULL, class, type, + answer, anslen)) > 0) + return (ret); + if (got_nodata) + h_errno = NO_DATA; + return (-1); +} + +/* + * Perform a call on res_query on the concatenation of name and domain, + * removing a trailing dot from name if domain is NULL. + */ +res_querydomain(name, domain, class, type, answer, anslen) + char *name, *domain; + int class, type; /* class and type of query */ + u_char *answer; /* buffer to put answer */ + int anslen; /* size of answer */ +{ + char nbuf[2*MAXDNAME+2]; + char *longname = nbuf; + int n; + +#ifdef DEBUG + if (_res.options & RES_DEBUG) + printf(";; res_querydomain(%s, %s, %d, %d)\n", + name, domain, class, type); +#endif + if (domain == NULL) { + /* + * Check for trailing '.'; + * copy without '.' if present. + */ + n = strlen(name) - 1; + if (name[n] == '.' && n < sizeof(nbuf) - 1) { + bcopy(name, nbuf, n); + nbuf[n] = '\0'; + } else + longname = name; + } else + (void)sprintf(nbuf, "%.*s.%.*s", + MAXDNAME, name, MAXDNAME, domain); + + return (res_query(longname, class, type, answer, anslen)); +} + +char * +__hostalias(name) + register const char *name; +{ + register char *C1, *C2; + FILE *fp; + char *file, *getenv(), *strcpy(), *strncpy(); + char buf[BUFSIZ]; + static char abuf[MAXDNAME]; + + file = getenv("HOSTALIASES"); + if (file == NULL || (fp = fopen(file, "r")) == NULL) + return (NULL); + buf[sizeof(buf) - 1] = '\0'; + while (fgets(buf, sizeof(buf), fp)) { + for (C1 = buf; *C1 && !isspace(*C1); ++C1); + if (!*C1) + break; + *C1 = '\0'; + if (!strcasecmp(buf, name)) { + while (isspace(*++C1)); + if (!*C1) + break; + for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2); + abuf[sizeof(abuf) - 1] = *C2 = '\0'; + (void)strncpy(abuf, C1, sizeof(abuf) - 1); + fclose(fp); + return (abuf); + } + } + fclose(fp); + return (NULL); +} |