Print this page
1926 libresolv evades compiler warnings
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libresolv/res_send.c
+++ new/usr/src/lib/libresolv/res_send.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 + * Copyright 2015 Gary Mills
23 24 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 25 * Use is subject to license terms.
25 26 */
26 27
27 28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 29 /* All Rights Reserved */
29 30
30 31 /*
31 32 * University Copyright- Copyright (c) 1982, 1986, 1988
32 33 * The Regents of the University of California
33 34 * All Rights Reserved
34 35 *
35 36 * University Acknowledgment- Portions of this document are derived from
36 37 * software developed by the University of California, Berkeley, and its
37 38 * contributors.
38 39 */
39 40
40 -#pragma ident "%Z%%M% %I% %E% SMI"
41 -
42 41 /*
43 42 * Send query to name server and wait for reply.
44 43 */
45 44
46 45 #include <sys/param.h>
47 46 #include <sys/time.h>
48 47 #include <sys/socket.h>
49 48 #include <sys/uio.h>
50 49 #include <sys/stat.h>
51 50 #include <netinet/in.h>
52 51 #include <stdio.h>
52 +#include <string.h>
53 +#include <unistd.h>
53 54 #include <errno.h>
54 55 #include <arpa/nameser.h>
56 +#include <arpa/inet.h>
55 57 #include <resolv.h>
58 +#include "crossl.h"
56 59
60 +/*
61 + * Undocumented external function in libsocket
62 + */
63 +extern int
64 +_socket(int, int, int);
57 65
58 66 static int s = -1; /* socket used for communications */
67 +#if BSD >= 43
59 68 static struct sockaddr no_addr;
69 +#endif /* BSD */
60 70
61 71
62 72 #ifndef FD_SET
63 73 #define NFDBITS 32
64 74 #define FD_SETSIZE 32
65 75 #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
66 76 #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
67 77 #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
68 78 #ifdef SYSV
69 -#define FD_ZERO(p) memset((void *)(p), 0, sizeof (*(p)))
79 +#define FD_ZERO(p) (void) memset((void *)(p), 0, sizeof (*(p)))
70 80 #else
71 81 #define FD_ZERO(p) bzero((char *)(p), sizeof (*(p)))
72 82 #endif
73 83 #endif
74 84
75 85 /*
76 86 * 1247019: Kludge to time out quickly if there is no /etc/resolv.conf
77 87 * and a TCP connection to the local DNS server fails.
78 88 */
79 89
80 90 static int _confcheck()
81 91 {
82 92 int ns;
83 93 struct stat rc_stat;
84 94 struct sockaddr_in ns_sin;
85 95
86 96
87 97 /* First, we check to see if /etc/resolv.conf exists.
88 98 * If it doesn't, then localhost is mostlikely to be
89 99 * the nameserver.
90 100 */
91 101 if (stat(_PATH_RESCONF, &rc_stat) == -1 && errno == ENOENT) {
92 102
93 103 /* Next, we check to see if _res.nsaddr is set to loopback.
94 104 * If it isn't, it has been altered by the application
95 105 * explicitly and we then want to bail with success.
96 106 */
97 107 if (_res.nsaddr.sin_addr.S_un.S_addr == htonl(INADDR_LOOPBACK)) {
98 108
99 109 /* Lastly, we try to connect to the TCP port of the
100 110 * nameserver. If this fails, then we know that
101 111 * DNS is misconfigured and we can quickly exit.
102 112 */
103 113 ns = socket(AF_INET, SOCK_STREAM, 0);
104 114 IN_SET_LOOPBACK_ADDR(&ns_sin);
105 115 ns_sin.sin_port = htons(NAMESERVER_PORT);
106 116 if (connect(ns, (struct sockaddr *) &ns_sin,
107 117 sizeof ns_sin) == -1) {
108 118 close(ns);
109 119 return(-1);
110 120 }
111 121 else {
112 122 close(ns);
113 123 return(0);
114 124 }
115 125 }
116 126
117 127 return(0);
118 128 }
119 129
120 130 return (0);
121 131 }
↓ open down ↓ |
42 lines elided |
↑ open up ↑ |
122 132
123 133 int
124 134 res_send(buf, buflen, answer, anslen)
125 135 char *buf;
126 136 int buflen;
127 137 char *answer;
128 138 int anslen;
129 139 {
130 140 register int n;
131 141 int try, v_circuit, resplen, ns;
132 - int gotsomewhere = 0, connected = 0;
142 + int gotsomewhere = 0;
143 +#if BSD >= 43
144 + int connected = 0;
145 +#endif /* BSD */
133 146 int connreset = 0;
134 147 u_short id, len;
135 148 char *cp;
136 149 fd_set dsmask;
137 150 struct timeval timeout;
138 151 HEADER *hp = (HEADER *) buf;
139 152 HEADER *anhp = (HEADER *) answer;
140 153 struct iovec iov[2];
141 154 int terrno = ETIMEDOUT;
142 155 char junk[512];
143 156
144 157 #ifdef DEBUG
145 158 if (_res.options & RES_DEBUG) {
146 159 printf("res_send()\n");
147 160 p_query(buf);
148 161 }
149 162 #endif
150 163 if (!(_res.options & RES_INIT))
151 164 if (res_init() == -1) {
152 165 return (-1);
153 166 }
154 167
155 168 /* 1247019: Check to see if we can bailout quickly. */
156 169 if (_confcheck() == -1)
157 170 return(-1);
158 171
159 172 v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
160 173 id = hp->id;
161 174 /*
162 175 * Send request, RETRY times, or until successful
163 176 */
164 177 for (try = 0; try < _res.retry; try++) {
165 178 for (ns = 0; ns < _res.nscount; ns++) {
166 179 #ifdef DEBUG
167 180 if (_res.options & RES_DEBUG)
168 181 printf("Querying server (# %d) address = %s\n",
169 182 ns+1, inet_ntoa(_res.nsaddr_list[ns].sin_addr));
170 183 #endif
171 184 usevc:
172 185 if (v_circuit) {
173 186 int truncated = 0;
174 187
175 188 /*
176 189 * Use virtual circuit;
177 190 * at most one attempt per server.
178 191 */
179 192 try = _res.retry;
180 193 if (s < 0) {
181 194 s = _socket(AF_INET, SOCK_STREAM, 0);
182 195 if (s < 0) {
183 196 terrno = errno;
184 197 #ifdef DEBUG
185 198 if (_res.options & RES_DEBUG) {
186 199 perror("socket (vc) failed");
187 200 }
188 201 #endif
189 202 continue;
190 203 }
191 204 if (connect(s, (struct sockaddr *) &_res.nsaddr_list[ns],
192 205 sizeof (struct sockaddr)) < 0) {
193 206 terrno = errno;
194 207 #ifdef DEBUG
195 208 if (_res.options & RES_DEBUG) {
196 209 perror("connect failed");
197 210 }
198 211 #endif
199 212 (void) close(s);
200 213 s = -1;
201 214 continue;
202 215 }
203 216 }
204 217 /*
205 218 * Send length & message
206 219 */
207 220 len = htons((u_short)buflen);
208 221 iov[0].iov_base = (caddr_t)&len;
209 222 iov[0].iov_len = sizeof (len);
210 223 iov[1].iov_base = buf;
211 224 iov[1].iov_len = buflen;
212 225 if (writev(s, iov, 2) != sizeof (len) +
213 226 buflen) {
214 227 terrno = errno;
215 228 #ifdef DEBUG
216 229 if (_res.options & RES_DEBUG)
217 230 perror("write failed");
218 231 #endif
219 232 (void) close(s);
220 233 s = -1;
221 234 continue;
222 235 }
223 236 /*
224 237 * Receive length & response
225 238 */
226 239 cp = answer;
227 240 len = sizeof (short);
228 241 while (len != 0 && (n = read
229 242 (s, (char *)cp, (int)len)) > 0) {
230 243 cp += n;
231 244 len -= n;
232 245 }
233 246 if (n <= 0) {
234 247 terrno = errno;
235 248 #ifdef DEBUG
236 249 if (_res.options & RES_DEBUG)
237 250 perror("read failed");
238 251 #endif
239 252 (void) close(s);
240 253 s = -1;
241 254 /*
242 255 * A long running process might get its TCP
243 256 * connection reset if the remote server was
244 257 * restarted. Requery the server instead of
245 258 * trying a new one. When there is only one
246 259 * server, this means that a query might work
247 260 * instead of failing. We only allow one reset
248 261 * per query to prevent looping.
249 262 */
250 263 if (terrno == ECONNRESET &&
251 264 !connreset) {
252 265 connreset = 1;
253 266 ns--;
254 267 }
255 268 continue;
256 269 }
257 270 cp = answer;
258 271 if ((resplen = ntohs(*(u_short *)cp)) >
259 272 anslen) {
260 273 #ifdef DEBUG
261 274 if (_res.options & RES_DEBUG)
262 275 fprintf(stderr,
263 276 "response truncated\n");
264 277 #endif
265 278 len = anslen;
266 279 truncated = 1;
267 280 } else
268 281 len = resplen;
269 282 while (len != 0 &&
270 283 (n = read(s, (char *)cp,
271 284 (int)len)) > 0) {
272 285 cp += n;
273 286 len -= n;
274 287 }
275 288 if (n <= 0) {
276 289 terrno = errno;
277 290 #ifdef DEBUG
278 291 if (_res.options & RES_DEBUG)
279 292 perror("read failed");
280 293 #endif
281 294 (void) close(s);
282 295 s = -1;
283 296 continue;
284 297 }
285 298 if (truncated) {
286 299 /*
287 300 * Flush rest of answer
288 301 * so connection stays in synch.
289 302 */
290 303 anhp->tc = 1;
291 304 len = resplen - anslen;
292 305 /*
293 306 * set the value of resplen to anslen,
294 307 * this is done because the caller
295 308 * assumes resplen contains the size of
296 309 * message read into the "answer" buffer
297 310 * passed in.
298 311 */
299 312 resplen = anslen;
300 313
301 314 while (len != 0) {
302 315 n = (len > sizeof (junk) ?
303 316 sizeof (junk) : len);
304 317 if ((n = read(s, junk, n)) > 0)
305 318 len -= n;
306 319 else
307 320 break;
308 321 }
309 322 }
310 323 } else {
311 324 /*
312 325 * Use datagrams.
313 326 */
314 327 if (s < 0) {
315 328 s = _socket(AF_INET, SOCK_DGRAM, 0);
316 329 if (s < 0) {
317 330 terrno = errno;
318 331 #ifdef DEBUG
319 332 if (_res.options & RES_DEBUG) {
320 333 perror("socket (dg) failed");
321 334 }
322 335 #endif
323 336 continue;
324 337 }
325 338 }
326 339 #if BSD >= 43
327 340 /*
328 341 * I'm tired of answering this question, so:
329 342 * On a 4.3BSD+ machine (client and server,
330 343 * actually), sending to a nameserver datagram
331 344 * port with no nameserver will cause an
332 345 * ICMP port unreachable message to be returned.
333 346 * If our datagram socket is "connected" to the
334 347 * server, we get an ECONNREFUSED error on the next
335 348 * socket operation, and select returns if the
336 349 * error message is received. We can thus detect
337 350 * the absence of a nameserver without timing out.
338 351 * If we have sent queries to at least two servers,
339 352 * however, we don't want to remain connected,
340 353 * as we wish to receive answers from the first
341 354 * server to respond.
342 355 */
343 356 if (_res.nscount == 1 ||
344 357 (try == 0 && ns == 0)) {
345 358 /*
346 359 * Don't use connect if we might
347 360 * still receive a response
348 361 * from another server.
349 362 */
350 363 if (connected == 0) {
351 364 if (connect(s,
352 365 (struct sockaddr *) &_res.nsaddr_list[ns],
353 366 sizeof (struct sockaddr)) < 0) {
354 367 #ifdef DEBUG
355 368 if (_res.options &
356 369 RES_DEBUG) {
357 370 perror("connect");
358 371 }
359 372 #endif
360 373 continue;
361 374 }
362 375 connected = 1;
363 376 }
364 377 if (send(s, buf, buflen, 0) != buflen) {
365 378 #ifdef DEBUG
366 379 if (_res.options & RES_DEBUG)
367 380 perror("send");
368 381 #endif
369 382 continue;
370 383 }
371 384 } else {
372 385 /*
373 386 * Disconnect if we want to listen for
374 387 * responses from more than one server.
375 388 */
376 389 if (connected) {
377 390 (void) connect(s, &no_addr,
378 391 sizeof (no_addr));
379 392 connected = 0;
380 393 }
381 394 #endif /* BSD */
382 395 if (sendto(s, buf, buflen, 0,
383 396 (struct sockaddr *) &_res.nsaddr_list[ns],
384 397 sizeof (struct sockaddr)) != buflen) {
385 398 #ifdef DEBUG
386 399 if (_res.options & RES_DEBUG)
387 400 perror("sendto");
388 401 #endif
389 402 continue;
390 403 }
391 404 #if BSD >= 43
392 405 }
393 406 #endif
394 407
395 408 /*
396 409 * Wait for reply
397 410 */
398 411 timeout.tv_sec = (_res.retrans << try);
399 412 if (try > 0)
400 413 timeout.tv_sec /= _res.nscount;
401 414 if (timeout.tv_sec <= 0)
402 415 timeout.tv_sec = 1;
403 416 timeout.tv_usec = 0;
404 417 wait:
405 418 FD_ZERO(&dsmask);
406 419 FD_SET(s, &dsmask);
407 420 n = select(s+1, &dsmask, (fd_set *)NULL,
408 421 (fd_set *)NULL, &timeout);
409 422 if (n < 0) {
410 423 #ifdef DEBUG
411 424 if (_res.options & RES_DEBUG)
412 425 perror("select");
413 426 #endif
414 427 continue;
415 428 }
416 429 if (n == 0) {
417 430 /*
418 431 * timeout
419 432 */
420 433 #ifdef DEBUG
421 434 if (_res.options & RES_DEBUG)
422 435 printf("timeout\n");
423 436 #endif
424 437 #if BSD >= 43
425 438 gotsomewhere = 1;
426 439 #endif
427 440 continue;
428 441 }
429 442 if ((resplen = recv(s, answer, anslen, 0))
430 443 <= 0) {
431 444 #ifdef DEBUG
432 445 if (_res.options & RES_DEBUG)
433 446 perror("recvfrom");
434 447 #endif
435 448 continue;
436 449 }
437 450 gotsomewhere = 1;
438 451 if (id != anhp->id) {
439 452 /*
440 453 * response from old query, ignore it
441 454 */
442 455 #ifdef DEBUG
443 456 if (_res.options & RES_DEBUG) {
444 457 printf("old answer:\n");
445 458 p_query(answer);
446 459 }
447 460 #endif
448 461 goto wait;
449 462 }
450 463 if (!(_res.options & RES_IGNTC) && anhp->tc) {
451 464 /*
452 465 * get rest of answer;
453 466 * use TCP with same server.
454 467 */
455 468 #ifdef DEBUG
456 469 if (_res.options & RES_DEBUG)
457 470 printf("truncated answer\n");
458 471 #endif
459 472 (void) close(s);
460 473 s = -1;
461 474 v_circuit = 1;
462 475 goto usevc;
463 476 }
464 477 }
465 478 #ifdef DEBUG
466 479 if (_res.options & RES_DEBUG) {
467 480 printf("got answer:\n");
468 481 p_query(answer);
469 482 }
470 483 #endif
471 484 /*
472 485 * If using virtual circuits, we assume that the first server
473 486 * is preferred * over the rest (i.e. it is on the local
474 487 * machine) and only keep that one open.
475 488 * If we have temporarily opened a virtual circuit,
476 489 * or if we haven't been asked to keep a socket open,
477 490 * close the socket.
478 491 */
479 492 if ((v_circuit &&
480 493 ((_res.options & RES_USEVC) == 0 || ns != 0)) ||
481 494 (_res.options & RES_STAYOPEN) == 0) {
482 495 (void) close(s);
483 496 s = -1;
484 497 }
485 498 return (resplen);
486 499 }
487 500 }
488 501 if (s >= 0) {
489 502 (void) close(s);
490 503 s = -1;
491 504 }
492 505 if (v_circuit == 0)
493 506 if (gotsomewhere == 0)
494 507 errno = ECONNREFUSED; /* no nameservers found */
495 508 else
496 509 errno = ETIMEDOUT; /* no answer obtained */
497 510 else
498 511 errno = terrno;
499 512 return (-1);
500 513 }
501 514
502 515 /*
503 516 * This routine is for closing the socket if a virtual circuit is used and
504 517 * the program wants to close it. This provides support for endhostent()
505 518 * which expects to close the socket.
506 519 *
507 520 * This routine is not expected to be user visible.
508 521 */
509 522 void
510 523 _res_close()
511 524 {
512 525 if (s != -1) {
513 526 (void) close(s);
514 527 s = -1;
515 528 }
516 529 }
↓ open down ↓ |
374 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX