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