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