1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1998 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  * University Copyright- Copyright (c) 1982, 1986, 1988
32  * The Regents of the University of California
33  * All Rights Reserved
34  *
35  * University Acknowledgment- Portions of this document are derived from
36  * software developed by the University of California, Berkeley, and its
37  * contributors.
38  */
39 
40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
41 
42 #include "synonyms.h"
43 
44 #include <stdio.h>
45 #include <sys/types.h>
46 #include <sys/socket.h>
47 #include <sys/stat.h>
48 #include <netinet/in.h>
49 #include <arpa/nameser.h>
50 #include <resolv.h>
51 #include <errno.h>
52 #include <netdb.h>
53 
54 /*
55  * Kludge to time out quickly if there is no /etc/resolv.conf
56  * and a TCP connection to the local DNS server fails.
57  *
58  * Moved function from res_send.c to res_mkquery.c.  This
59  * solves a long timeout problem with nslookup.
60  *
61  * __areweinnamed is needed because there is a possibility that the
62  * user might do bad things to resolv.conf and cause in.named to call
63  * _confcheck and deadlock the server.
64  */
65 
66 int __areweinnamed()
67 {
68 	return (0);
69 }
70 
71 static int _confcheck()
72 {
73 	int ns;
74 	struct stat rc_stat;
75 	struct sockaddr_in ns_sin;
76 
77 
78 	/* First, we check to see if /etc/resolv.conf exists.
79 	 * If it doesn't, then localhost is mostlikely to be
80 	 * the nameserver.
81 	 */
82 	if (stat(_PATH_RESCONF, &rc_stat) == -1 && errno == ENOENT) {
83 
84 		/* Next, we check to see if _res.nsaddr is set to loopback.
85 		 * If it isn't, it has been altered by the application
86 		 * explicitly and we then want to bail with success.
87 		 */
88 		if (__areweinnamed())
89 			return (0);
90 
91 		if (_res.nsaddr.sin_addr.S_un.S_addr == htonl(INADDR_LOOPBACK)) {
92 
93 			/* Lastly, we try to connect to the TCP port of the
94 			 * nameserver.  If this fails, then we know that
95 			 * DNS is misconfigured and we can quickly exit.
96 			 */
97 			ns = socket(AF_INET, SOCK_STREAM, 0);
98 			IN_SET_LOOPBACK_ADDR(&ns_sin);
99 			ns_sin.sin_port = htons(NAMESERVER_PORT);
100 			if (connect(ns, (struct sockaddr *) &ns_sin,
101 				    sizeof ns_sin) == -1) {
102 				close(ns);
103 				return(-1);
104 			}
105 			else {
106 				close(ns);
107 				return(0);
108 			}
109 		}
110 
111 		return(0);
112 	}
113 
114 	return (0);
115 }
116 
117 /*
118  * Form all types of queries.
119  * Returns the size of the result or -1.
120  */
121 res_mkquery(op, dname, class, type, data, datalen, newrr, buf, buflen)
122 	int op;			/* opcode of query */
123 	char *dname;		/* domain name */
124 	int class, type;	/* class and type of query */
125 	char *data;		/* resource record data */
126 	int datalen;		/* length of data */
127 	struct rrec *newrr;	/* new rr for modify or append */
128 	char *buf;		/* buffer to put query */
129 	int buflen;		/* size of buffer */
130 {
131 	register HEADER *hp;
132 	register char *cp;
133 	register int n;
134 	char *dnptrs[10], **dpp, **lastdnptr;
135 
136 #ifdef DEBUG
137 	if (_res.options & RES_DEBUG)
138 		printf("res_mkquery(%d, %s, %d, %d)\n", op, dname, class, type);
139 #endif DEBUG
140 
141 	/*
142 	 * Check to see if we can bailout quickly.
143 	 * Also rerun res_init if we failed in the past.
144 	 */
145 
146 	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
147 		h_errno = NO_RECOVERY;
148 		return(-1);
149 	}
150 
151 	if (_confcheck() == -1) {
152 		_res.options &= ~RES_INIT;
153 		h_errno = NO_RECOVERY;
154 		return(-1);
155 	}
156 
157 	/*
158 	 * Initialize header fields.
159 	 */
160 	if ((buf == NULL) || (buflen < sizeof (HEADER)))
161 		return (-1);
162 #ifdef SYSV
163 	memset(buf, 0, sizeof (HEADER));
164 #else
165 	bzero(buf, sizeof (HEADER));
166 #endif
167 	hp = (HEADER *) buf;
168 	hp->id = htons(++_res.id);
169 	hp->opcode = op;
170 	hp->pr = (_res.options & RES_PRIMARY) != 0;
171 	hp->rd = (_res.options & RES_RECURSE) != 0;
172 	hp->rcode = NOERROR;
173 	cp = buf + sizeof (HEADER);
174 	buflen -= sizeof (HEADER);
175 	dpp = dnptrs;
176 	*dpp++ = buf;
177 	*dpp++ = NULL;
178 	lastdnptr = dnptrs + sizeof (dnptrs) / sizeof (dnptrs[0]);
179 	/*
180 	 * perform opcode specific processing
181 	 */
182 	switch (op) {
183 	case QUERY:
184 		if ((buflen -= QFIXEDSZ) < 0)
185 			return (-1);
186 		if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
187 			return (-1);
188 		cp += n;
189 		buflen -= n;
190 		putshort(type, cp);
191 		cp += sizeof (u_short);
192 		putshort(class, cp);
193 		cp += sizeof (u_short);
194 		hp->qdcount = htons(1);
195 		if (op == QUERY || data == NULL)
196 			break;
197 		/*
198 		 * Make an additional record for completion domain.
199 		 */
200 		buflen -= RRFIXEDSZ;
201 		if ((n = dn_comp(data, cp, buflen, dnptrs, lastdnptr)) < 0)
202 			return (-1);
203 		cp += n;
204 		buflen -= n;
205 		putshort(T_NULL, cp);
206 		cp += sizeof (u_short);
207 		putshort(class, cp);
208 		cp += sizeof (u_short);
209 		putlong(0, cp);
210 		cp += sizeof (u_long);
211 		putshort(0, cp);
212 		cp += sizeof (u_short);
213 		hp->arcount = htons(1);
214 		break;
215 
216 	case IQUERY:
217 		/*
218 		 * Initialize answer section
219 		 */
220 		if (buflen < 1 + RRFIXEDSZ + datalen)
221 			return (-1);
222 		*cp++ = '\0';	/* no domain name */
223 		putshort(type, cp);
224 		cp += sizeof (u_short);
225 		putshort(class, cp);
226 		cp += sizeof (u_short);
227 		putlong(0, cp);
228 		cp += sizeof (u_long);
229 		putshort(datalen, cp);
230 		cp += sizeof (u_short);
231 		if (datalen) {
232 #ifdef SYSV
233 			memcpy((void *)cp, (void *)data, datalen);
234 #else
235 			bcopy(data, cp, datalen);
236 #endif
237 			cp += datalen;
238 		}
239 		hp->ancount = htons(1);
240 		break;
241 
242 #ifdef ALLOW_UPDATES
243 	/*
244 	 * For UPDATEM/UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA
245 	 * (Record to be modified is followed by its replacement in msg.)
246 	 */
247 	case UPDATEM:
248 	case UPDATEMA:
249 
250 	case UPDATED:
251 		/*
252 		 * The res code for UPDATED and UPDATEDA is the same; user
253 		 * calls them differently: specifies data for UPDATED; server
254 		 * ignores data if specified for UPDATEDA.
255 		 */
256 	case UPDATEDA:
257 		buflen -= RRFIXEDSZ + datalen;
258 		if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
259 			return (-1);
260 		cp += n;
261 		putshort(type, cp);
262 		cp += sizeof (u_short);
263 		putshort(class, cp);
264 		cp += sizeof (u_short);
265 		putlong(0, cp);
266 		cp += sizeof (u_long);
267 		putshort(datalen, cp);
268 		cp += sizeof (u_short);
269 		if (datalen) {
270 #ifdef SYSV
271 			memcpy((void *)cp, (void *)data, datalen);
272 #else
273 			bcopy(data, cp, datalen);
274 #endif
275 			cp += datalen;
276 		}
277 		if ((op == UPDATED) || (op == UPDATEDA)) {
278 			hp->ancount = htons(0);
279 			break;
280 		}
281 		/* Else UPDATEM/UPDATEMA, so drop into code for UPDATEA */
282 
283 	case UPDATEA:	/* Add new resource record */
284 		buflen -= RRFIXEDSZ + datalen;
285 		if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
286 			return (-1);
287 		cp += n;
288 		putshort(newrr->r_type, cp);
289 		cp += sizeof (u_short);
290 		putshort(newrr->r_class, cp);
291 		cp += sizeof (u_short);
292 		putlong(0, cp);
293 		cp += sizeof (u_long);
294 		putshort(newrr->r_size, cp);
295 		cp += sizeof (u_short);
296 		if (newrr->r_size) {
297 #ifdef SYSV
298 			memcpy((void *)cp, newrr->r_data, newrr->r_size);
299 #else
300 			bcopy(newrr->r_data, cp, newrr->r_size);
301 #endif
302 			cp += newrr->r_size;
303 		}
304 		hp->ancount = htons(0);
305 		break;
306 
307 #endif ALLOW_UPDATES
308 	}
309 	return (cp - buf);
310 }
311