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
__areweinnamed()64 int __areweinnamed()
65 {
66 return (0);
67 }
68
_confcheck()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
res_mkquery(op,dname,class,type,data,datalen,newrr,buf,buflen)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