1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 29 /* All Rights Reserved */ 30 31 /* 32 * University Copyright- Copyright (c) 1982, 1986, 1988 33 * The Regents of the University of California 34 * All Rights Reserved 35 * 36 * University Acknowledgment- Portions of this document are derived from 37 * software developed by the University of California, Berkeley, and its 38 * contributors. 39 */ 40 41 #pragma ident "%Z%%M% %I% %E% SMI" 42 43 #include "c_synonyms.h" 44 #include <sys/param.h> 45 #include <sys/socket.h> 46 #include <netinet/in.h> 47 #include <ctype.h> 48 #include <netdb.h> 49 #include <stdio.h> 50 #include <errno.h> 51 #include <string.h> 52 #include <arpa/inet.h> 53 #include <arpa/nameser.h> 54 #include <resolv.h> 55 56 #if PACKETSZ > 1024 57 #define MAXPACKET PACKETSZ 58 #else 59 #define MAXPACKET 1024 60 #endif 61 62 int h_errno; 63 64 /* 65 * Formulate a normal query, send, and await answer. 66 * Returned answer is placed in supplied buffer "answer". 67 * Perform preliminary check of answer, returning success only 68 * if no error is indicated and the answer count is nonzero. 69 * Return the size of the response on success, -1 on error. 70 * Error number is left in h_errno. 71 * Caller must parse answer and determine whether it answers the question. 72 */ 73 int 74 res_query(name, class, type, answer, anslen) 75 char *name; /* domain name */ 76 int class, type; /* class and type of query */ 77 u_char *answer; /* buffer to put answer */ 78 int anslen; /* size of answer buffer */ 79 { 80 char buf[MAXPACKET]; 81 HEADER *hp; 82 int n; 83 84 if ((_res.options & RES_INIT) == 0 && res_init() == -1) 85 return (-1); 86 #ifdef DEBUG 87 if (_res.options & RES_DEBUG) 88 printf("res_query(%s, %d, %d)\n", name, class, type); 89 #endif 90 n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0, NULL, 91 buf, sizeof (buf)); 92 93 if (n <= 0) { 94 #ifdef DEBUG 95 if (_res.options & RES_DEBUG) 96 printf("res_query: mkquery failed\n"); 97 #endif 98 h_errno = NO_RECOVERY; 99 return (n); 100 } 101 n = res_send(buf, n, answer, anslen); 102 if (n < 0) { 103 #ifdef DEBUG 104 if (_res.options & RES_DEBUG) 105 printf("res_query: send error\n"); 106 #endif 107 h_errno = TRY_AGAIN; 108 return (n); 109 } 110 111 hp = (HEADER *) answer; 112 if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { 113 #ifdef DEBUG 114 if (_res.options & RES_DEBUG) 115 printf("rcode = %d, ancount=%d\n", hp->rcode, 116 ntohs(hp->ancount)); 117 #endif 118 switch (hp->rcode) { 119 case NXDOMAIN: 120 h_errno = HOST_NOT_FOUND; 121 break; 122 case SERVFAIL: 123 h_errno = TRY_AGAIN; 124 break; 125 case NOERROR: 126 h_errno = NO_DATA; 127 break; 128 case FORMERR: 129 case NOTIMP: 130 case REFUSED: 131 default: 132 h_errno = NO_RECOVERY; 133 break; 134 } 135 return (-1); 136 } 137 if (hp->rcode == NOERROR && ntohs(hp->ancount) > 0) 138 h_errno = 0; 139 return (n); 140 } 141 142 /* 143 * Formulate a normal query, send, and retrieve answer in supplied buffer. 144 * Return the size of the response on success, -1 on error. 145 * If enabled, implement search rules until answer or unrecoverable failure 146 * is detected. Error number is left in h_errno. 147 * Only useful for queries in the same name hierarchy as the local host 148 * (not, for example, for host address-to-name lookups in domain in-addr.arpa). 149 */ 150 int 151 res_search(name, class, type, answer, anslen) 152 char *name; /* domain name */ 153 int class, type; /* class and type of query */ 154 u_char *answer; /* buffer to put answer */ 155 int anslen; /* size of answer */ 156 { 157 register char *cp, **domain; 158 int n, ret, got_nodata = 0; 159 char *hostalias(); 160 161 if ((_res.options & RES_INIT) == 0 && res_init() == -1) 162 return (-1); 163 164 errno = 0; 165 h_errno = HOST_NOT_FOUND; /* default, if we never query */ 166 for (cp = name, n = 0; *cp; cp++) 167 if (*cp == '.') 168 n++; 169 if (n == 0 && (cp = hostalias(name))) 170 return (res_query(cp, class, type, answer, anslen)); 171 172 /* 173 * We do at least one level of search if 174 * - there is no dot and RES_DEFNAME is set, or 175 * - there is at least one dot, there is no trailing dot, 176 * and RES_DNSRCH is set. 177 */ 178 if ((n == 0 && _res.options & RES_DEFNAMES) || 179 (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH)) { 180 for (domain = _res.dnsrch; *domain; domain++) { 181 ret = res_querydomain(name, *domain, class, type, 182 answer, anslen); 183 if (ret > 0) 184 return (ret); 185 /* 186 * If no server present, give up. 187 * If name isn't found in this domain, 188 * keep trying higher domains in the search list 189 * (if that's enabled). 190 * On a NO_DATA error, keep trying, otherwise 191 * a wildcard entry of another type could keep us 192 * from finding this entry higher in the domain. 193 * If we get some other error (negative answer or 194 * server failure), then stop searching up, 195 * but try the input name below in case it's fully-qualified. 196 */ 197 if (errno == ECONNREFUSED) { 198 h_errno = TRY_AGAIN; 199 return (-1); 200 } 201 if (h_errno == NO_DATA) 202 got_nodata++; 203 if ((h_errno != HOST_NOT_FOUND && h_errno != NO_DATA) || 204 (_res.options & RES_DNSRCH) == 0) 205 break; 206 } 207 } 208 /* 209 * If the search/default failed, try the name as fully-qualified, 210 * but only if it contained at least one dot (even trailing). 211 * This is purely a heuristic; we assume that any reasonable query 212 * about a top-level domain (for servers, SOA, etc) will not use 213 * res_search. 214 */ 215 if (n && (ret = res_querydomain(name, (char *)NULL, class, type, 216 answer, anslen)) > 0) 217 return (ret); 218 if (got_nodata) 219 h_errno = NO_DATA; 220 return (-1); 221 } 222 223 /* 224 * Perform a call on res_query on the concatenation of name and domain, 225 * removing a trailing dot from name if domain is NULL. 226 */ 227 int 228 res_querydomain(name, domain, class, type, answer, anslen) 229 char *name, *domain; 230 int class, type; /* class and type of query */ 231 u_char *answer; /* buffer to put answer */ 232 int anslen; /* size of answer */ 233 { 234 char nbuf[2*MAXDNAME+2]; 235 char *longname = nbuf; 236 int n; 237 238 #ifdef DEBUG 239 if (_res.options & RES_DEBUG) { 240 if (domain == (char *)NULL) 241 printf("res_querydomain(%s, NULL, %d, %d)\n", 242 name, class, type); 243 else 244 printf("res_querydomain(%s, %s, %d, %d)\n", 245 name, domain, class, type); 246 } 247 #endif 248 if (domain == NULL) { 249 /* 250 * Check for trailing '.'; 251 * copy without '.' if present. 252 */ 253 n = strlen(name) - 1; 254 if (name[n] == '.' && n < sizeof (nbuf) - 1) { 255 #ifdef SYSV 256 memcpy((void *)nbuf, (void *)name, n); 257 #else 258 bcopy(name, nbuf, n); 259 #endif 260 nbuf[n] = '\0'; 261 } else 262 longname = name; 263 } else 264 (void) sprintf(nbuf, "%.*s.%.*s", 265 MAXDNAME, name, MAXDNAME, domain); 266 267 return (res_query(longname, class, type, answer, anslen)); 268 } 269 270 char * 271 hostalias(name) 272 register char *name; 273 { 274 register char *C1, *C2; 275 FILE *fp; 276 char *file, *getenv(), *strcpy(), *strncpy(); 277 char buf[BUFSIZ]; 278 static char abuf[MAXDNAME]; 279 280 file = getenv("HOSTALIASES"); 281 if (file == NULL || (fp = fopen(file, "r")) == NULL) 282 return (NULL); 283 buf[sizeof (buf) - 1] = '\0'; 284 while (fgets(buf, sizeof (buf), fp)) { 285 for (C1 = buf; *C1 && !isspace(*C1); ++C1); 286 if (!*C1) 287 break; 288 *C1 = '\0'; 289 if (!strcasecmp(buf, name)) { 290 while (isspace(*++C1)); 291 if (!*C1) 292 break; 293 for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2); 294 abuf[sizeof (abuf) - 1] = *C2 = '\0'; 295 (void) strncpy(abuf, C1, sizeof (abuf) - 1); 296 fclose(fp); 297 return (abuf); 298 } 299 } 300 fclose(fp); 301 return (NULL); 302 } 303