res_mkquery.c revision 1219:f89f56c2d9ac
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/*
24 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
25 * Use is subject to license terms.
26 */
27
28/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29/*	  All Rights Reserved  	*/
30
31/*
32 * University Copyright- Copyright (c) 1982, 1986, 1988
33 * The Regents of the University of California
34 * All Rights Reserved
35 *
36 * University Acknowledgment- Portions of this document are derived from
37 * software developed by the University of California, Berkeley, and its
38 * contributors.
39 */
40
41#pragma ident	"%Z%%M%	%I%	%E% SMI"
42
43#include "c_synonyms.h"
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
66int __areweinnamed()
67{
68	return (0);
69}
70
71static 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 */
121int
122res_mkquery(op, dname, class, type, data, datalen, newrr, buf, buflen)
123	int op;			/* opcode of query */
124	char *dname;		/* domain name */
125	int class, type;	/* class and type of query */
126	char *data;		/* resource record data */
127	int datalen;		/* length of data */
128	struct rrec *newrr;	/* new rr for modify or append */
129	char *buf;		/* buffer to put query */
130	int buflen;		/* size of buffer */
131{
132	register HEADER *hp;
133	register char *cp;
134	register int n;
135	char *dnptrs[10], **dpp, **lastdnptr;
136
137#ifdef DEBUG
138	if (_res.options & RES_DEBUG)
139		printf("res_mkquery(%d, %s, %d, %d)\n", op, dname, class, type);
140#endif /* DEBUG */
141
142	/*
143	 * Check to see if we can bailout quickly.
144	 * Also rerun res_init if we failed in the past.
145	 */
146
147	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
148		h_errno = NO_RECOVERY;
149		return(-1);
150	}
151
152	if (_confcheck() == -1) {
153		_res.options &= ~RES_INIT;
154		h_errno = NO_RECOVERY;
155		return(-1);
156	}
157
158	/*
159	 * Initialize header fields.
160	 */
161	if ((buf == NULL) || (buflen < sizeof (HEADER)))
162		return (-1);
163#ifdef SYSV
164	memset(buf, 0, sizeof (HEADER));
165#else
166	bzero(buf, sizeof (HEADER));
167#endif
168	hp = (HEADER *) buf;
169	hp->id = htons(++_res.id);
170	hp->opcode = op;
171	hp->pr = (_res.options & RES_PRIMARY) != 0;
172	hp->rd = (_res.options & RES_RECURSE) != 0;
173	hp->rcode = NOERROR;
174	cp = buf + sizeof (HEADER);
175	buflen -= sizeof (HEADER);
176	dpp = dnptrs;
177	*dpp++ = buf;
178	*dpp++ = NULL;
179	lastdnptr = dnptrs + sizeof (dnptrs) / sizeof (dnptrs[0]);
180	/*
181	 * perform opcode specific processing
182	 */
183	switch (op) {
184	case QUERY:
185		if ((buflen -= QFIXEDSZ) < 0)
186			return (-1);
187		if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
188			return (-1);
189		cp += n;
190		buflen -= n;
191		putshort(type, cp);
192		cp += sizeof (u_short);
193		putshort(class, cp);
194		cp += sizeof (u_short);
195		hp->qdcount = htons(1);
196		if (op == QUERY || data == NULL)
197			break;
198		/*
199		 * Make an additional record for completion domain.
200		 */
201		buflen -= RRFIXEDSZ;
202		if ((n = dn_comp(data, cp, buflen, dnptrs, lastdnptr)) < 0)
203			return (-1);
204		cp += n;
205		buflen -= n;
206		putshort(T_NULL, cp);
207		cp += sizeof (u_short);
208		putshort(class, cp);
209		cp += sizeof (u_short);
210		putlong(0, cp);
211		cp += sizeof (u_long);
212		putshort(0, cp);
213		cp += sizeof (u_short);
214		hp->arcount = htons(1);
215		break;
216
217	case IQUERY:
218		/*
219		 * Initialize answer section
220		 */
221		if (buflen < 1 + RRFIXEDSZ + datalen)
222			return (-1);
223		*cp++ = '\0';	/* no domain name */
224		putshort(type, cp);
225		cp += sizeof (u_short);
226		putshort(class, cp);
227		cp += sizeof (u_short);
228		putlong(0, cp);
229		cp += sizeof (u_long);
230		putshort(datalen, cp);
231		cp += sizeof (u_short);
232		if (datalen) {
233#ifdef SYSV
234			memcpy((void *)cp, (void *)data, datalen);
235#else
236			bcopy(data, cp, datalen);
237#endif
238			cp += datalen;
239		}
240		hp->ancount = htons(1);
241		break;
242
243#ifdef ALLOW_UPDATES
244	/*
245	 * For UPDATEM/UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA
246	 * (Record to be modified is followed by its replacement in msg.)
247	 */
248	case UPDATEM:
249	case UPDATEMA:
250
251	case UPDATED:
252		/*
253		 * The res code for UPDATED and UPDATEDA is the same; user
254		 * calls them differently: specifies data for UPDATED; server
255		 * ignores data if specified for UPDATEDA.
256		 */
257	case UPDATEDA:
258		buflen -= RRFIXEDSZ + datalen;
259		if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
260			return (-1);
261		cp += n;
262		putshort(type, cp);
263		cp += sizeof (u_short);
264		putshort(class, cp);
265		cp += sizeof (u_short);
266		putlong(0, cp);
267		cp += sizeof (u_long);
268		putshort(datalen, cp);
269		cp += sizeof (u_short);
270		if (datalen) {
271#ifdef SYSV
272			memcpy((void *)cp, (void *)data, datalen);
273#else
274			bcopy(data, cp, datalen);
275#endif
276			cp += datalen;
277		}
278		if ((op == UPDATED) || (op == UPDATEDA)) {
279			hp->ancount = htons(0);
280			break;
281		}
282		/* Else UPDATEM/UPDATEMA, so drop into code for UPDATEA */
283
284	case UPDATEA:	/* Add new resource record */
285		buflen -= RRFIXEDSZ + datalen;
286		if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
287			return (-1);
288		cp += n;
289		putshort(newrr->r_type, cp);
290		cp += sizeof (u_short);
291		putshort(newrr->r_class, cp);
292		cp += sizeof (u_short);
293		putlong(0, cp);
294		cp += sizeof (u_long);
295		putshort(newrr->r_size, cp);
296		cp += sizeof (u_short);
297		if (newrr->r_size) {
298#ifdef SYSV
299			memcpy((void *)cp, newrr->r_data, newrr->r_size);
300#else
301			bcopy(newrr->r_data, cp, newrr->r_size);
302#endif
303			cp += newrr->r_size;
304		}
305		hp->ancount = htons(0);
306		break;
307
308#endif /* ALLOW_UPDATES */
309	}
310	return (cp - buf);
311}
312