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