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