10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*6812Sraf * Common Development and Distribution License (the "License").
6*6812Sraf * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
211219Sraf
220Sstevel@tonic-gate /*
23*6812Sraf * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
280Sstevel@tonic-gate /* All Rights Reserved */
290Sstevel@tonic-gate
300Sstevel@tonic-gate /*
310Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988
320Sstevel@tonic-gate * The Regents of the University of California
330Sstevel@tonic-gate * All Rights Reserved
340Sstevel@tonic-gate *
350Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from
360Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its
370Sstevel@tonic-gate * contributors.
380Sstevel@tonic-gate */
390Sstevel@tonic-gate
400Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
410Sstevel@tonic-gate
420Sstevel@tonic-gate #include <sys/param.h>
430Sstevel@tonic-gate #include <sys/socket.h>
440Sstevel@tonic-gate #include <netinet/in.h>
450Sstevel@tonic-gate #include <ctype.h>
460Sstevel@tonic-gate #include <netdb.h>
470Sstevel@tonic-gate #include <stdio.h>
480Sstevel@tonic-gate #include <errno.h>
490Sstevel@tonic-gate #include <string.h>
500Sstevel@tonic-gate #include <arpa/inet.h>
510Sstevel@tonic-gate #include <arpa/nameser.h>
520Sstevel@tonic-gate #include <resolv.h>
530Sstevel@tonic-gate
540Sstevel@tonic-gate #if PACKETSZ > 1024
550Sstevel@tonic-gate #define MAXPACKET PACKETSZ
560Sstevel@tonic-gate #else
570Sstevel@tonic-gate #define MAXPACKET 1024
580Sstevel@tonic-gate #endif
590Sstevel@tonic-gate
600Sstevel@tonic-gate int h_errno;
610Sstevel@tonic-gate
620Sstevel@tonic-gate /*
630Sstevel@tonic-gate * Formulate a normal query, send, and await answer.
640Sstevel@tonic-gate * Returned answer is placed in supplied buffer "answer".
650Sstevel@tonic-gate * Perform preliminary check of answer, returning success only
660Sstevel@tonic-gate * if no error is indicated and the answer count is nonzero.
670Sstevel@tonic-gate * Return the size of the response on success, -1 on error.
680Sstevel@tonic-gate * Error number is left in h_errno.
690Sstevel@tonic-gate * Caller must parse answer and determine whether it answers the question.
700Sstevel@tonic-gate */
71237Sanay int
res_query(name,class,type,answer,anslen)720Sstevel@tonic-gate res_query(name, class, type, answer, anslen)
730Sstevel@tonic-gate char *name; /* domain name */
740Sstevel@tonic-gate int class, type; /* class and type of query */
750Sstevel@tonic-gate u_char *answer; /* buffer to put answer */
760Sstevel@tonic-gate int anslen; /* size of answer buffer */
770Sstevel@tonic-gate {
780Sstevel@tonic-gate char buf[MAXPACKET];
790Sstevel@tonic-gate HEADER *hp;
800Sstevel@tonic-gate int n;
810Sstevel@tonic-gate
820Sstevel@tonic-gate if ((_res.options & RES_INIT) == 0 && res_init() == -1)
830Sstevel@tonic-gate return (-1);
840Sstevel@tonic-gate #ifdef DEBUG
850Sstevel@tonic-gate if (_res.options & RES_DEBUG)
860Sstevel@tonic-gate printf("res_query(%s, %d, %d)\n", name, class, type);
870Sstevel@tonic-gate #endif
880Sstevel@tonic-gate n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0, NULL,
890Sstevel@tonic-gate buf, sizeof (buf));
900Sstevel@tonic-gate
910Sstevel@tonic-gate if (n <= 0) {
920Sstevel@tonic-gate #ifdef DEBUG
930Sstevel@tonic-gate if (_res.options & RES_DEBUG)
940Sstevel@tonic-gate printf("res_query: mkquery failed\n");
950Sstevel@tonic-gate #endif
960Sstevel@tonic-gate h_errno = NO_RECOVERY;
970Sstevel@tonic-gate return (n);
980Sstevel@tonic-gate }
990Sstevel@tonic-gate n = res_send(buf, n, answer, anslen);
1000Sstevel@tonic-gate if (n < 0) {
1010Sstevel@tonic-gate #ifdef DEBUG
1020Sstevel@tonic-gate if (_res.options & RES_DEBUG)
1030Sstevel@tonic-gate printf("res_query: send error\n");
1040Sstevel@tonic-gate #endif
1050Sstevel@tonic-gate h_errno = TRY_AGAIN;
1060Sstevel@tonic-gate return (n);
1070Sstevel@tonic-gate }
1080Sstevel@tonic-gate
1090Sstevel@tonic-gate hp = (HEADER *) answer;
1100Sstevel@tonic-gate if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
1110Sstevel@tonic-gate #ifdef DEBUG
1120Sstevel@tonic-gate if (_res.options & RES_DEBUG)
1130Sstevel@tonic-gate printf("rcode = %d, ancount=%d\n", hp->rcode,
1140Sstevel@tonic-gate ntohs(hp->ancount));
1150Sstevel@tonic-gate #endif
1160Sstevel@tonic-gate switch (hp->rcode) {
1170Sstevel@tonic-gate case NXDOMAIN:
1180Sstevel@tonic-gate h_errno = HOST_NOT_FOUND;
1190Sstevel@tonic-gate break;
1200Sstevel@tonic-gate case SERVFAIL:
1210Sstevel@tonic-gate h_errno = TRY_AGAIN;
1220Sstevel@tonic-gate break;
1230Sstevel@tonic-gate case NOERROR:
1240Sstevel@tonic-gate h_errno = NO_DATA;
1250Sstevel@tonic-gate break;
1260Sstevel@tonic-gate case FORMERR:
1270Sstevel@tonic-gate case NOTIMP:
1280Sstevel@tonic-gate case REFUSED:
1290Sstevel@tonic-gate default:
1300Sstevel@tonic-gate h_errno = NO_RECOVERY;
1310Sstevel@tonic-gate break;
1320Sstevel@tonic-gate }
1330Sstevel@tonic-gate return (-1);
1340Sstevel@tonic-gate }
1350Sstevel@tonic-gate if (hp->rcode == NOERROR && ntohs(hp->ancount) > 0)
1360Sstevel@tonic-gate h_errno = 0;
1370Sstevel@tonic-gate return (n);
1380Sstevel@tonic-gate }
1390Sstevel@tonic-gate
1400Sstevel@tonic-gate /*
1410Sstevel@tonic-gate * Formulate a normal query, send, and retrieve answer in supplied buffer.
1420Sstevel@tonic-gate * Return the size of the response on success, -1 on error.
1430Sstevel@tonic-gate * If enabled, implement search rules until answer or unrecoverable failure
1440Sstevel@tonic-gate * is detected. Error number is left in h_errno.
1450Sstevel@tonic-gate * Only useful for queries in the same name hierarchy as the local host
1460Sstevel@tonic-gate * (not, for example, for host address-to-name lookups in domain in-addr.arpa).
1470Sstevel@tonic-gate */
148237Sanay int
res_search(name,class,type,answer,anslen)1490Sstevel@tonic-gate res_search(name, class, type, answer, anslen)
1500Sstevel@tonic-gate char *name; /* domain name */
1510Sstevel@tonic-gate int class, type; /* class and type of query */
1520Sstevel@tonic-gate u_char *answer; /* buffer to put answer */
1530Sstevel@tonic-gate int anslen; /* size of answer */
1540Sstevel@tonic-gate {
1550Sstevel@tonic-gate register char *cp, **domain;
1560Sstevel@tonic-gate int n, ret, got_nodata = 0;
1570Sstevel@tonic-gate char *hostalias();
1580Sstevel@tonic-gate
1590Sstevel@tonic-gate if ((_res.options & RES_INIT) == 0 && res_init() == -1)
1600Sstevel@tonic-gate return (-1);
1610Sstevel@tonic-gate
1620Sstevel@tonic-gate errno = 0;
1630Sstevel@tonic-gate h_errno = HOST_NOT_FOUND; /* default, if we never query */
1640Sstevel@tonic-gate for (cp = name, n = 0; *cp; cp++)
1650Sstevel@tonic-gate if (*cp == '.')
1660Sstevel@tonic-gate n++;
1670Sstevel@tonic-gate if (n == 0 && (cp = hostalias(name)))
1680Sstevel@tonic-gate return (res_query(cp, class, type, answer, anslen));
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate /*
1710Sstevel@tonic-gate * We do at least one level of search if
1720Sstevel@tonic-gate * - there is no dot and RES_DEFNAME is set, or
1730Sstevel@tonic-gate * - there is at least one dot, there is no trailing dot,
1740Sstevel@tonic-gate * and RES_DNSRCH is set.
1750Sstevel@tonic-gate */
1760Sstevel@tonic-gate if ((n == 0 && _res.options & RES_DEFNAMES) ||
1770Sstevel@tonic-gate (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH)) {
1780Sstevel@tonic-gate for (domain = _res.dnsrch; *domain; domain++) {
1790Sstevel@tonic-gate ret = res_querydomain(name, *domain, class, type,
1800Sstevel@tonic-gate answer, anslen);
1810Sstevel@tonic-gate if (ret > 0)
1820Sstevel@tonic-gate return (ret);
1830Sstevel@tonic-gate /*
1840Sstevel@tonic-gate * If no server present, give up.
1850Sstevel@tonic-gate * If name isn't found in this domain,
1860Sstevel@tonic-gate * keep trying higher domains in the search list
1870Sstevel@tonic-gate * (if that's enabled).
1880Sstevel@tonic-gate * On a NO_DATA error, keep trying, otherwise
1890Sstevel@tonic-gate * a wildcard entry of another type could keep us
1900Sstevel@tonic-gate * from finding this entry higher in the domain.
1910Sstevel@tonic-gate * If we get some other error (negative answer or
1920Sstevel@tonic-gate * server failure), then stop searching up,
1930Sstevel@tonic-gate * but try the input name below in case it's fully-qualified.
1940Sstevel@tonic-gate */
1950Sstevel@tonic-gate if (errno == ECONNREFUSED) {
1960Sstevel@tonic-gate h_errno = TRY_AGAIN;
1970Sstevel@tonic-gate return (-1);
1980Sstevel@tonic-gate }
1990Sstevel@tonic-gate if (h_errno == NO_DATA)
2000Sstevel@tonic-gate got_nodata++;
2010Sstevel@tonic-gate if ((h_errno != HOST_NOT_FOUND && h_errno != NO_DATA) ||
2020Sstevel@tonic-gate (_res.options & RES_DNSRCH) == 0)
2030Sstevel@tonic-gate break;
2040Sstevel@tonic-gate }
2050Sstevel@tonic-gate }
2060Sstevel@tonic-gate /*
2070Sstevel@tonic-gate * If the search/default failed, try the name as fully-qualified,
2080Sstevel@tonic-gate * but only if it contained at least one dot (even trailing).
2090Sstevel@tonic-gate * This is purely a heuristic; we assume that any reasonable query
2100Sstevel@tonic-gate * about a top-level domain (for servers, SOA, etc) will not use
2110Sstevel@tonic-gate * res_search.
2120Sstevel@tonic-gate */
2130Sstevel@tonic-gate if (n && (ret = res_querydomain(name, (char *)NULL, class, type,
2140Sstevel@tonic-gate answer, anslen)) > 0)
2150Sstevel@tonic-gate return (ret);
2160Sstevel@tonic-gate if (got_nodata)
2170Sstevel@tonic-gate h_errno = NO_DATA;
2180Sstevel@tonic-gate return (-1);
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate
2210Sstevel@tonic-gate /*
2220Sstevel@tonic-gate * Perform a call on res_query on the concatenation of name and domain,
2230Sstevel@tonic-gate * removing a trailing dot from name if domain is NULL.
2240Sstevel@tonic-gate */
225237Sanay int
res_querydomain(name,domain,class,type,answer,anslen)2260Sstevel@tonic-gate res_querydomain(name, domain, class, type, answer, anslen)
2270Sstevel@tonic-gate char *name, *domain;
2280Sstevel@tonic-gate int class, type; /* class and type of query */
2290Sstevel@tonic-gate u_char *answer; /* buffer to put answer */
2300Sstevel@tonic-gate int anslen; /* size of answer */
2310Sstevel@tonic-gate {
2320Sstevel@tonic-gate char nbuf[2*MAXDNAME+2];
2330Sstevel@tonic-gate char *longname = nbuf;
2340Sstevel@tonic-gate int n;
2350Sstevel@tonic-gate
2360Sstevel@tonic-gate #ifdef DEBUG
2370Sstevel@tonic-gate if (_res.options & RES_DEBUG) {
2380Sstevel@tonic-gate if (domain == (char *)NULL)
2390Sstevel@tonic-gate printf("res_querydomain(%s, NULL, %d, %d)\n",
2400Sstevel@tonic-gate name, class, type);
2410Sstevel@tonic-gate else
2420Sstevel@tonic-gate printf("res_querydomain(%s, %s, %d, %d)\n",
2430Sstevel@tonic-gate name, domain, class, type);
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate #endif
2460Sstevel@tonic-gate if (domain == NULL) {
2470Sstevel@tonic-gate /*
2480Sstevel@tonic-gate * Check for trailing '.';
2490Sstevel@tonic-gate * copy without '.' if present.
2500Sstevel@tonic-gate */
2510Sstevel@tonic-gate n = strlen(name) - 1;
2520Sstevel@tonic-gate if (name[n] == '.' && n < sizeof (nbuf) - 1) {
2530Sstevel@tonic-gate #ifdef SYSV
2540Sstevel@tonic-gate memcpy((void *)nbuf, (void *)name, n);
2550Sstevel@tonic-gate #else
2560Sstevel@tonic-gate bcopy(name, nbuf, n);
2570Sstevel@tonic-gate #endif
2580Sstevel@tonic-gate nbuf[n] = '\0';
2590Sstevel@tonic-gate } else
2600Sstevel@tonic-gate longname = name;
2610Sstevel@tonic-gate } else
2620Sstevel@tonic-gate (void) sprintf(nbuf, "%.*s.%.*s",
2630Sstevel@tonic-gate MAXDNAME, name, MAXDNAME, domain);
2640Sstevel@tonic-gate
2650Sstevel@tonic-gate return (res_query(longname, class, type, answer, anslen));
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate char *
hostalias(name)2690Sstevel@tonic-gate hostalias(name)
2700Sstevel@tonic-gate register char *name;
2710Sstevel@tonic-gate {
2720Sstevel@tonic-gate register char *C1, *C2;
2730Sstevel@tonic-gate FILE *fp;
2740Sstevel@tonic-gate char *file, *getenv(), *strcpy(), *strncpy();
2750Sstevel@tonic-gate char buf[BUFSIZ];
2760Sstevel@tonic-gate static char abuf[MAXDNAME];
2770Sstevel@tonic-gate
2780Sstevel@tonic-gate file = getenv("HOSTALIASES");
2790Sstevel@tonic-gate if (file == NULL || (fp = fopen(file, "r")) == NULL)
2800Sstevel@tonic-gate return (NULL);
2810Sstevel@tonic-gate buf[sizeof (buf) - 1] = '\0';
2820Sstevel@tonic-gate while (fgets(buf, sizeof (buf), fp)) {
2830Sstevel@tonic-gate for (C1 = buf; *C1 && !isspace(*C1); ++C1);
2840Sstevel@tonic-gate if (!*C1)
2850Sstevel@tonic-gate break;
2860Sstevel@tonic-gate *C1 = '\0';
2870Sstevel@tonic-gate if (!strcasecmp(buf, name)) {
2880Sstevel@tonic-gate while (isspace(*++C1));
2890Sstevel@tonic-gate if (!*C1)
2900Sstevel@tonic-gate break;
2910Sstevel@tonic-gate for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2);
2920Sstevel@tonic-gate abuf[sizeof (abuf) - 1] = *C2 = '\0';
2930Sstevel@tonic-gate (void) strncpy(abuf, C1, sizeof (abuf) - 1);
2940Sstevel@tonic-gate fclose(fp);
2950Sstevel@tonic-gate return (abuf);
2960Sstevel@tonic-gate }
2970Sstevel@tonic-gate }
2980Sstevel@tonic-gate fclose(fp);
2990Sstevel@tonic-gate return (NULL);
3000Sstevel@tonic-gate }
301