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