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