1 /*- 2 * Copyright (c) 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * - 7 * Portions Copyright (c) 1993 by Digital Equipment Corporation. 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies, and that 12 * the name of Digital Equipment Corporation not be used in advertising or 13 * publicity pertaining to distribution of the document or software without 14 * specific, written prior permission. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL 17 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT 19 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 20 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 21 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 22 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 23 * SOFTWARE. 24 * - 25 * --Copyright-- 26 */ 27 28 #if defined(LIBC_SCCS) && !defined(lint) 29 static char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 06/04/93"; 30 static char rcsid[] = "$Id: res_query.c,v 1.1 1993/06/01 09:42:14 vixie Exp vixie $"; 31 #endif /* LIBC_SCCS and not lint */ 32 33 #include <sys/param.h> 34 #include <netinet/in.h> 35 #include <arpa/inet.h> 36 #include <arpa/nameser.h> 37 #include <netdb.h> 38 #include <resolv.h> 39 #include <stdio.h> 40 #include <ctype.h> 41 #include <errno.h> 42 #include <stdlib.h> 43 #include <string.h> 44 45 #if PACKETSZ > 1024 46 #define MAXPACKET PACKETSZ 47 #else 48 #define MAXPACKET 1024 49 #endif 50 51 int h_errno; 52 53 /* 54 * Formulate a normal query, send, and await answer. 55 * Returned answer is placed in supplied buffer "answer". 56 * Perform preliminary check of answer, returning success only 57 * if no error is indicated and the answer count is nonzero. 58 * Return the size of the response on success, -1 on error. 59 * Error number is left in h_errno. 60 * Caller must parse answer and determine whether it answers the question. 61 */ 62 res_query(name, class, type, answer, anslen) 63 char *name; /* domain name */ 64 int class, type; /* class and type of query */ 65 u_char *answer; /* buffer to put answer */ 66 int anslen; /* size of answer buffer */ 67 { 68 char buf[MAXPACKET]; 69 HEADER *hp; 70 int n; 71 72 if ((_res.options & RES_INIT) == 0 && res_init() == -1) 73 return (-1); 74 #ifdef DEBUG 75 if (_res.options & RES_DEBUG) 76 printf(";; res_query(%s, %d, %d)\n", name, class, type); 77 #endif 78 n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0, NULL, 79 buf, sizeof(buf)); 80 81 if (n <= 0) { 82 #ifdef DEBUG 83 if (_res.options & RES_DEBUG) 84 printf(";; res_query: mkquery failed\n"); 85 #endif 86 h_errno = NO_RECOVERY; 87 return (n); 88 } 89 n = res_send(buf, n, (char *)answer, anslen); 90 if (n < 0) { 91 #ifdef DEBUG 92 if (_res.options & RES_DEBUG) 93 printf(";; res_query: send error\n"); 94 #endif 95 h_errno = TRY_AGAIN; 96 return(n); 97 } 98 99 hp = (HEADER *) answer; 100 if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { 101 #ifdef DEBUG 102 if (_res.options & RES_DEBUG) 103 printf(";; rcode = %d, ancount=%d\n", hp->rcode, 104 ntohs(hp->ancount)); 105 #endif 106 switch (hp->rcode) { 107 case NXDOMAIN: 108 h_errno = HOST_NOT_FOUND; 109 break; 110 case SERVFAIL: 111 h_errno = TRY_AGAIN; 112 break; 113 case NOERROR: 114 h_errno = NO_DATA; 115 break; 116 case FORMERR: 117 case NOTIMP: 118 case REFUSED: 119 default: 120 h_errno = NO_RECOVERY; 121 break; 122 } 123 return (-1); 124 } 125 return(n); 126 } 127 128 /* 129 * Formulate a normal query, send, and retrieve answer in supplied buffer. 130 * Return the size of the response on success, -1 on error. 131 * If enabled, implement search rules until answer or unrecoverable failure 132 * is detected. Error number is left in h_errno. 133 * Only useful for queries in the same name hierarchy as the local host 134 * (not, for example, for host address-to-name lookups in domain in-addr.arpa). 135 */ 136 int 137 res_search(name, class, type, answer, anslen) 138 char *name; /* domain name */ 139 int class, type; /* class and type of query */ 140 u_char *answer; /* buffer to put answer */ 141 int anslen; /* size of answer */ 142 { 143 register char *cp, **domain; 144 int n, ret, got_nodata = 0; 145 char *__hostalias(); 146 147 if ((_res.options & RES_INIT) == 0 && res_init() == -1) 148 return (-1); 149 150 errno = 0; 151 h_errno = HOST_NOT_FOUND; /* default, if we never query */ 152 for (cp = name, n = 0; *cp; cp++) 153 if (*cp == '.') 154 n++; 155 if (n == 0 && (cp = __hostalias(name))) 156 return (res_query(cp, class, type, answer, anslen)); 157 158 /* 159 * We do at least one level of search if 160 * - there is no dot and RES_DEFNAME is set, or 161 * - there is at least one dot, there is no trailing dot, 162 * and RES_DNSRCH is set. 163 */ 164 if ((n == 0 && _res.options & RES_DEFNAMES) || 165 (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH)) 166 for (domain = _res.dnsrch; *domain; domain++) { 167 ret = res_querydomain(name, *domain, class, type, 168 answer, anslen); 169 if (ret > 0) 170 return (ret); 171 /* 172 * If no server present, give up. 173 * If name isn't found in this domain, 174 * keep trying higher domains in the search list 175 * (if that's enabled). 176 * On a NO_DATA error, keep trying, otherwise 177 * a wildcard entry of another type could keep us 178 * from finding this entry higher in the domain. 179 * If we get some other error (negative answer or 180 * server failure), then stop searching up, 181 * but try the input name below in case it's fully-qualified. 182 */ 183 if (errno == ECONNREFUSED) { 184 h_errno = TRY_AGAIN; 185 return (-1); 186 } 187 if (h_errno == NO_DATA) 188 got_nodata++; 189 if ((h_errno != HOST_NOT_FOUND && h_errno != NO_DATA) || 190 (_res.options & RES_DNSRCH) == 0) 191 break; 192 } 193 /* 194 * If the search/default failed, try the name as fully-qualified, 195 * but only if it contained at least one dot (even trailing). 196 * This is purely a heuristic; we assume that any reasonable query 197 * about a top-level domain (for servers, SOA, etc) will not use 198 * res_search. 199 */ 200 if (n && (ret = res_querydomain(name, (char *)NULL, class, type, 201 answer, anslen)) > 0) 202 return (ret); 203 if (got_nodata) 204 h_errno = NO_DATA; 205 return (-1); 206 } 207 208 /* 209 * Perform a call on res_query on the concatenation of name and domain, 210 * removing a trailing dot from name if domain is NULL. 211 */ 212 res_querydomain(name, domain, class, type, answer, anslen) 213 char *name, *domain; 214 int class, type; /* class and type of query */ 215 u_char *answer; /* buffer to put answer */ 216 int anslen; /* size of answer */ 217 { 218 char nbuf[2*MAXDNAME+2]; 219 char *longname = nbuf; 220 int n; 221 222 #ifdef DEBUG 223 if (_res.options & RES_DEBUG) 224 printf(";; res_querydomain(%s, %s, %d, %d)\n", 225 name, domain, class, type); 226 #endif 227 if (domain == NULL) { 228 /* 229 * Check for trailing '.'; 230 * copy without '.' if present. 231 */ 232 n = strlen(name) - 1; 233 if (name[n] == '.' && n < sizeof(nbuf) - 1) { 234 bcopy(name, nbuf, n); 235 nbuf[n] = '\0'; 236 } else 237 longname = name; 238 } else 239 (void)sprintf(nbuf, "%.*s.%.*s", 240 MAXDNAME, name, MAXDNAME, domain); 241 242 return (res_query(longname, class, type, answer, anslen)); 243 } 244 245 char * 246 __hostalias(name) 247 register const char *name; 248 { 249 register char *C1, *C2; 250 FILE *fp; 251 char *file, *getenv(), *strcpy(), *strncpy(); 252 char buf[BUFSIZ]; 253 static char abuf[MAXDNAME]; 254 255 file = getenv("HOSTALIASES"); 256 if (file == NULL || (fp = fopen(file, "r")) == NULL) 257 return (NULL); 258 buf[sizeof(buf) - 1] = '\0'; 259 while (fgets(buf, sizeof(buf), fp)) { 260 for (C1 = buf; *C1 && !isspace(*C1); ++C1); 261 if (!*C1) 262 break; 263 *C1 = '\0'; 264 if (!strcasecmp(buf, name)) { 265 while (isspace(*++C1)); 266 if (!*C1) 267 break; 268 for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2); 269 abuf[sizeof(abuf) - 1] = *C2 = '\0'; 270 (void)strncpy(abuf, C1, sizeof(abuf) - 1); 271 fclose(fp); 272 return (abuf); 273 } 274 } 275 fclose(fp); 276 return (NULL); 277 } 278