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