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