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 1998 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 <stdio.h>
45*0Sstevel@tonic-gate #include <sys/types.h>
46*0Sstevel@tonic-gate #include <sys/socket.h>
47*0Sstevel@tonic-gate #include <sys/stat.h>
48*0Sstevel@tonic-gate #include <netinet/in.h>
49*0Sstevel@tonic-gate #include <arpa/nameser.h>
50*0Sstevel@tonic-gate #include <resolv.h>
51*0Sstevel@tonic-gate #include <errno.h>
52*0Sstevel@tonic-gate #include <netdb.h>
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate /*
55*0Sstevel@tonic-gate  * Kludge to time out quickly if there is no /etc/resolv.conf
56*0Sstevel@tonic-gate  * and a TCP connection to the local DNS server fails.
57*0Sstevel@tonic-gate  *
58*0Sstevel@tonic-gate  * Moved function from res_send.c to res_mkquery.c.  This
59*0Sstevel@tonic-gate  * solves a long timeout problem with nslookup.
60*0Sstevel@tonic-gate  *
61*0Sstevel@tonic-gate  * __areweinnamed is needed because there is a possibility that the
62*0Sstevel@tonic-gate  * user might do bad things to resolv.conf and cause in.named to call
63*0Sstevel@tonic-gate  * _confcheck and deadlock the server.
64*0Sstevel@tonic-gate  */
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate int __areweinnamed()
67*0Sstevel@tonic-gate {
68*0Sstevel@tonic-gate 	return (0);
69*0Sstevel@tonic-gate }
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate static int _confcheck()
72*0Sstevel@tonic-gate {
73*0Sstevel@tonic-gate 	int ns;
74*0Sstevel@tonic-gate 	struct stat rc_stat;
75*0Sstevel@tonic-gate 	struct sockaddr_in ns_sin;
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate 	/* First, we check to see if /etc/resolv.conf exists.
79*0Sstevel@tonic-gate 	 * If it doesn't, then localhost is mostlikely to be
80*0Sstevel@tonic-gate 	 * the nameserver.
81*0Sstevel@tonic-gate 	 */
82*0Sstevel@tonic-gate 	if (stat(_PATH_RESCONF, &rc_stat) == -1 && errno == ENOENT) {
83*0Sstevel@tonic-gate 
84*0Sstevel@tonic-gate 		/* Next, we check to see if _res.nsaddr is set to loopback.
85*0Sstevel@tonic-gate 		 * If it isn't, it has been altered by the application
86*0Sstevel@tonic-gate 		 * explicitly and we then want to bail with success.
87*0Sstevel@tonic-gate 		 */
88*0Sstevel@tonic-gate 		if (__areweinnamed())
89*0Sstevel@tonic-gate 			return (0);
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate 		if (_res.nsaddr.sin_addr.S_un.S_addr == htonl(INADDR_LOOPBACK)) {
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate 			/* Lastly, we try to connect to the TCP port of the
94*0Sstevel@tonic-gate 			 * nameserver.  If this fails, then we know that
95*0Sstevel@tonic-gate 			 * DNS is misconfigured and we can quickly exit.
96*0Sstevel@tonic-gate 			 */
97*0Sstevel@tonic-gate 			ns = socket(AF_INET, SOCK_STREAM, 0);
98*0Sstevel@tonic-gate 			IN_SET_LOOPBACK_ADDR(&ns_sin);
99*0Sstevel@tonic-gate 			ns_sin.sin_port = htons(NAMESERVER_PORT);
100*0Sstevel@tonic-gate 			if (connect(ns, (struct sockaddr *) &ns_sin,
101*0Sstevel@tonic-gate 				    sizeof ns_sin) == -1) {
102*0Sstevel@tonic-gate 				close(ns);
103*0Sstevel@tonic-gate 				return(-1);
104*0Sstevel@tonic-gate 			}
105*0Sstevel@tonic-gate 			else {
106*0Sstevel@tonic-gate 				close(ns);
107*0Sstevel@tonic-gate 				return(0);
108*0Sstevel@tonic-gate 			}
109*0Sstevel@tonic-gate 		}
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 		return(0);
112*0Sstevel@tonic-gate 	}
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate 	return (0);
115*0Sstevel@tonic-gate }
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate /*
118*0Sstevel@tonic-gate  * Form all types of queries.
119*0Sstevel@tonic-gate  * Returns the size of the result or -1.
120*0Sstevel@tonic-gate  */
121*0Sstevel@tonic-gate res_mkquery(op, dname, class, type, data, datalen, newrr, buf, buflen)
122*0Sstevel@tonic-gate 	int op;			/* opcode of query */
123*0Sstevel@tonic-gate 	char *dname;		/* domain name */
124*0Sstevel@tonic-gate 	int class, type;	/* class and type of query */
125*0Sstevel@tonic-gate 	char *data;		/* resource record data */
126*0Sstevel@tonic-gate 	int datalen;		/* length of data */
127*0Sstevel@tonic-gate 	struct rrec *newrr;	/* new rr for modify or append */
128*0Sstevel@tonic-gate 	char *buf;		/* buffer to put query */
129*0Sstevel@tonic-gate 	int buflen;		/* size of buffer */
130*0Sstevel@tonic-gate {
131*0Sstevel@tonic-gate 	register HEADER *hp;
132*0Sstevel@tonic-gate 	register char *cp;
133*0Sstevel@tonic-gate 	register int n;
134*0Sstevel@tonic-gate 	char *dnptrs[10], **dpp, **lastdnptr;
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate #ifdef DEBUG
137*0Sstevel@tonic-gate 	if (_res.options & RES_DEBUG)
138*0Sstevel@tonic-gate 		printf("res_mkquery(%d, %s, %d, %d)\n", op, dname, class, type);
139*0Sstevel@tonic-gate #endif DEBUG
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate 	/*
142*0Sstevel@tonic-gate 	 * Check to see if we can bailout quickly.
143*0Sstevel@tonic-gate 	 * Also rerun res_init if we failed in the past.
144*0Sstevel@tonic-gate 	 */
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate 	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
147*0Sstevel@tonic-gate 		h_errno = NO_RECOVERY;
148*0Sstevel@tonic-gate 		return(-1);
149*0Sstevel@tonic-gate 	}
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate 	if (_confcheck() == -1) {
152*0Sstevel@tonic-gate 		_res.options &= ~RES_INIT;
153*0Sstevel@tonic-gate 		h_errno = NO_RECOVERY;
154*0Sstevel@tonic-gate 		return(-1);
155*0Sstevel@tonic-gate 	}
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate 	/*
158*0Sstevel@tonic-gate 	 * Initialize header fields.
159*0Sstevel@tonic-gate 	 */
160*0Sstevel@tonic-gate 	if ((buf == NULL) || (buflen < sizeof (HEADER)))
161*0Sstevel@tonic-gate 		return (-1);
162*0Sstevel@tonic-gate #ifdef SYSV
163*0Sstevel@tonic-gate 	memset(buf, 0, sizeof (HEADER));
164*0Sstevel@tonic-gate #else
165*0Sstevel@tonic-gate 	bzero(buf, sizeof (HEADER));
166*0Sstevel@tonic-gate #endif
167*0Sstevel@tonic-gate 	hp = (HEADER *) buf;
168*0Sstevel@tonic-gate 	hp->id = htons(++_res.id);
169*0Sstevel@tonic-gate 	hp->opcode = op;
170*0Sstevel@tonic-gate 	hp->pr = (_res.options & RES_PRIMARY) != 0;
171*0Sstevel@tonic-gate 	hp->rd = (_res.options & RES_RECURSE) != 0;
172*0Sstevel@tonic-gate 	hp->rcode = NOERROR;
173*0Sstevel@tonic-gate 	cp = buf + sizeof (HEADER);
174*0Sstevel@tonic-gate 	buflen -= sizeof (HEADER);
175*0Sstevel@tonic-gate 	dpp = dnptrs;
176*0Sstevel@tonic-gate 	*dpp++ = buf;
177*0Sstevel@tonic-gate 	*dpp++ = NULL;
178*0Sstevel@tonic-gate 	lastdnptr = dnptrs + sizeof (dnptrs) / sizeof (dnptrs[0]);
179*0Sstevel@tonic-gate 	/*
180*0Sstevel@tonic-gate 	 * perform opcode specific processing
181*0Sstevel@tonic-gate 	 */
182*0Sstevel@tonic-gate 	switch (op) {
183*0Sstevel@tonic-gate 	case QUERY:
184*0Sstevel@tonic-gate 		if ((buflen -= QFIXEDSZ) < 0)
185*0Sstevel@tonic-gate 			return (-1);
186*0Sstevel@tonic-gate 		if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
187*0Sstevel@tonic-gate 			return (-1);
188*0Sstevel@tonic-gate 		cp += n;
189*0Sstevel@tonic-gate 		buflen -= n;
190*0Sstevel@tonic-gate 		putshort(type, cp);
191*0Sstevel@tonic-gate 		cp += sizeof (u_short);
192*0Sstevel@tonic-gate 		putshort(class, cp);
193*0Sstevel@tonic-gate 		cp += sizeof (u_short);
194*0Sstevel@tonic-gate 		hp->qdcount = htons(1);
195*0Sstevel@tonic-gate 		if (op == QUERY || data == NULL)
196*0Sstevel@tonic-gate 			break;
197*0Sstevel@tonic-gate 		/*
198*0Sstevel@tonic-gate 		 * Make an additional record for completion domain.
199*0Sstevel@tonic-gate 		 */
200*0Sstevel@tonic-gate 		buflen -= RRFIXEDSZ;
201*0Sstevel@tonic-gate 		if ((n = dn_comp(data, cp, buflen, dnptrs, lastdnptr)) < 0)
202*0Sstevel@tonic-gate 			return (-1);
203*0Sstevel@tonic-gate 		cp += n;
204*0Sstevel@tonic-gate 		buflen -= n;
205*0Sstevel@tonic-gate 		putshort(T_NULL, cp);
206*0Sstevel@tonic-gate 		cp += sizeof (u_short);
207*0Sstevel@tonic-gate 		putshort(class, cp);
208*0Sstevel@tonic-gate 		cp += sizeof (u_short);
209*0Sstevel@tonic-gate 		putlong(0, cp);
210*0Sstevel@tonic-gate 		cp += sizeof (u_long);
211*0Sstevel@tonic-gate 		putshort(0, cp);
212*0Sstevel@tonic-gate 		cp += sizeof (u_short);
213*0Sstevel@tonic-gate 		hp->arcount = htons(1);
214*0Sstevel@tonic-gate 		break;
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 	case IQUERY:
217*0Sstevel@tonic-gate 		/*
218*0Sstevel@tonic-gate 		 * Initialize answer section
219*0Sstevel@tonic-gate 		 */
220*0Sstevel@tonic-gate 		if (buflen < 1 + RRFIXEDSZ + datalen)
221*0Sstevel@tonic-gate 			return (-1);
222*0Sstevel@tonic-gate 		*cp++ = '\0';	/* no domain name */
223*0Sstevel@tonic-gate 		putshort(type, cp);
224*0Sstevel@tonic-gate 		cp += sizeof (u_short);
225*0Sstevel@tonic-gate 		putshort(class, cp);
226*0Sstevel@tonic-gate 		cp += sizeof (u_short);
227*0Sstevel@tonic-gate 		putlong(0, cp);
228*0Sstevel@tonic-gate 		cp += sizeof (u_long);
229*0Sstevel@tonic-gate 		putshort(datalen, cp);
230*0Sstevel@tonic-gate 		cp += sizeof (u_short);
231*0Sstevel@tonic-gate 		if (datalen) {
232*0Sstevel@tonic-gate #ifdef SYSV
233*0Sstevel@tonic-gate 			memcpy((void *)cp, (void *)data, datalen);
234*0Sstevel@tonic-gate #else
235*0Sstevel@tonic-gate 			bcopy(data, cp, datalen);
236*0Sstevel@tonic-gate #endif
237*0Sstevel@tonic-gate 			cp += datalen;
238*0Sstevel@tonic-gate 		}
239*0Sstevel@tonic-gate 		hp->ancount = htons(1);
240*0Sstevel@tonic-gate 		break;
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate #ifdef ALLOW_UPDATES
243*0Sstevel@tonic-gate 	/*
244*0Sstevel@tonic-gate 	 * For UPDATEM/UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA
245*0Sstevel@tonic-gate 	 * (Record to be modified is followed by its replacement in msg.)
246*0Sstevel@tonic-gate 	 */
247*0Sstevel@tonic-gate 	case UPDATEM:
248*0Sstevel@tonic-gate 	case UPDATEMA:
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 	case UPDATED:
251*0Sstevel@tonic-gate 		/*
252*0Sstevel@tonic-gate 		 * The res code for UPDATED and UPDATEDA is the same; user
253*0Sstevel@tonic-gate 		 * calls them differently: specifies data for UPDATED; server
254*0Sstevel@tonic-gate 		 * ignores data if specified for UPDATEDA.
255*0Sstevel@tonic-gate 		 */
256*0Sstevel@tonic-gate 	case UPDATEDA:
257*0Sstevel@tonic-gate 		buflen -= RRFIXEDSZ + datalen;
258*0Sstevel@tonic-gate 		if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
259*0Sstevel@tonic-gate 			return (-1);
260*0Sstevel@tonic-gate 		cp += n;
261*0Sstevel@tonic-gate 		putshort(type, cp);
262*0Sstevel@tonic-gate 		cp += sizeof (u_short);
263*0Sstevel@tonic-gate 		putshort(class, cp);
264*0Sstevel@tonic-gate 		cp += sizeof (u_short);
265*0Sstevel@tonic-gate 		putlong(0, cp);
266*0Sstevel@tonic-gate 		cp += sizeof (u_long);
267*0Sstevel@tonic-gate 		putshort(datalen, cp);
268*0Sstevel@tonic-gate 		cp += sizeof (u_short);
269*0Sstevel@tonic-gate 		if (datalen) {
270*0Sstevel@tonic-gate #ifdef SYSV
271*0Sstevel@tonic-gate 			memcpy((void *)cp, (void *)data, datalen);
272*0Sstevel@tonic-gate #else
273*0Sstevel@tonic-gate 			bcopy(data, cp, datalen);
274*0Sstevel@tonic-gate #endif
275*0Sstevel@tonic-gate 			cp += datalen;
276*0Sstevel@tonic-gate 		}
277*0Sstevel@tonic-gate 		if ((op == UPDATED) || (op == UPDATEDA)) {
278*0Sstevel@tonic-gate 			hp->ancount = htons(0);
279*0Sstevel@tonic-gate 			break;
280*0Sstevel@tonic-gate 		}
281*0Sstevel@tonic-gate 		/* Else UPDATEM/UPDATEMA, so drop into code for UPDATEA */
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 	case UPDATEA:	/* Add new resource record */
284*0Sstevel@tonic-gate 		buflen -= RRFIXEDSZ + datalen;
285*0Sstevel@tonic-gate 		if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
286*0Sstevel@tonic-gate 			return (-1);
287*0Sstevel@tonic-gate 		cp += n;
288*0Sstevel@tonic-gate 		putshort(newrr->r_type, cp);
289*0Sstevel@tonic-gate 		cp += sizeof (u_short);
290*0Sstevel@tonic-gate 		putshort(newrr->r_class, cp);
291*0Sstevel@tonic-gate 		cp += sizeof (u_short);
292*0Sstevel@tonic-gate 		putlong(0, cp);
293*0Sstevel@tonic-gate 		cp += sizeof (u_long);
294*0Sstevel@tonic-gate 		putshort(newrr->r_size, cp);
295*0Sstevel@tonic-gate 		cp += sizeof (u_short);
296*0Sstevel@tonic-gate 		if (newrr->r_size) {
297*0Sstevel@tonic-gate #ifdef SYSV
298*0Sstevel@tonic-gate 			memcpy((void *)cp, newrr->r_data, newrr->r_size);
299*0Sstevel@tonic-gate #else
300*0Sstevel@tonic-gate 			bcopy(newrr->r_data, cp, newrr->r_size);
301*0Sstevel@tonic-gate #endif
302*0Sstevel@tonic-gate 			cp += newrr->r_size;
303*0Sstevel@tonic-gate 		}
304*0Sstevel@tonic-gate 		hp->ancount = htons(0);
305*0Sstevel@tonic-gate 		break;
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate #endif ALLOW_UPDATES
308*0Sstevel@tonic-gate 	}
309*0Sstevel@tonic-gate 	return (cp - buf);
310*0Sstevel@tonic-gate }
311