1 /*
2  * Copyright (c) 1985, 1989, 1993
3  *    The Regents of the University of California.  All rights reserved.
4  *
5  * Portions copyright (c) 1999, 2000
6  * Intel Corporation.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *
23  *    This product includes software developed by the University of
24  *    California, Berkeley, Intel Corporation, and its contributors.
25  *
26  * 4. Neither the name of University, Intel Corporation, or their respective
27  *    contributors may be used to endorse or promote products derived from
28  *    this software without specific prior written permission.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE REGENTS, INTEL CORPORATION AND
31  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
32  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
33  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS,
34  * INTEL CORPORATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
35  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
40  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41  *
42  */
43 
44 /*
45  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
46  *
47  * Permission to use, copy, modify, and distribute this software for any
48  * purpose with or without fee is hereby granted, provided that the above
49  * copyright notice and this permission notice appear in all copies, and that
50  * the name of Digital Equipment Corporation not be used in advertising or
51  * publicity pertaining to distribution of the document or software without
52  * specific, written prior permission.
53  *
54  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
55  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
56  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
57  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
58  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
59  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
60  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
61  * SOFTWARE.
62  */
63 
64 /*
65  * Portions Copyright (c) 1996 by Internet Software Consortium.
66  *
67  * Permission to use, copy, modify, and distribute this software for any
68  * purpose with or without fee is hereby granted, provided that the above
69  * copyright notice and this permission notice appear in all copies.
70  *
71  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
72  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
73  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
74  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
75  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
76  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
77  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
78  * SOFTWARE.
79  */
80 
81 #if defined(LIBC_SCCS) && !defined(lint)
82 static char sccsid[] = "@(#)res_send.c  8.1 (Berkeley) 6/4/93";
83 static char orig_rcsid[] = "From: Id: res_send.c,v 8.20 1998/04/06 23:27:51 halley Exp $";
84 static char rcsid[] = "$Id: res_send.c,v 1.1.1.1 2003/11/19 01:51:39 kyu3 Exp $";
85 #endif /* LIBC_SCCS and not lint */
86 
87 /*
88  * Send query to name server and wait for reply.
89  */
90 
91 #include <sys/types.h>
92 #include <sys/param.h>
93 #include <sys/select.h>
94 #include <sys/socket.h>
95 #include <sys/time.h>
96 #include <sys/uio.h>
97 
98 #include <netinet/in.h>
99 #include <arpa/nameser.h>
100 #include <arpa/inet.h>
101 
102 #include <errno.h>
103 #include <netdb.h>
104 #include <resolv.h>
105 #include <stdio.h>
106 #include <stdlib.h>
107 #include <string.h>
108 #include <unistd.h>
109 
110 #include "res_config.h"
111 
112 #ifndef _ORG_FREEBSD_
113 #define NOPOLL
114 #endif
115 
116 #ifdef NOPOLL           /* libc_r doesn't wrap poll yet() */
117 #else
118 #include <poll.h>
119 static int use_poll = 1;    /* adapt to poll() syscall availability */
120                 /* 0 = not present, 1 = try it, 2 = exists */
121 #endif
122 
123 static int s = -1;      /* socket used for communications */
124 static int connected = 0;   /* is the socket connected */
125 static int vc = 0;      /* is the socket a virtual circuit? */
126 static res_send_qhook Qhook = NULL;
127 static res_send_rhook Rhook = NULL;
128 
129 
130 #define CAN_RECONNECT 1
131 
132 #ifndef DEBUG
133 #   define Dprint(cond, args) /*empty*/
134 #   define DprintQ(cond, args, query, size) /*empty*/
135 #   define Aerror(file, string, error, address) /*empty*/
136 #   define Perror(file, string, error) /*empty*/
137 #else
138 #   define Dprint(cond, args) if (cond) {fprintf args;} else {}
139 #   define DprintQ(cond, args, query, size) if (cond) {\
140             fprintf args;\
141             __fp_nquery(query, size, stdout);\
142         } else {}
143 
144 static void
Aerror(FILE * file,char * string,int error,struct sockaddr_in address)145 Aerror(
146     FILE *file,
147     char *string,
148     int error,
149     struct sockaddr_in address
150     )
151 {
152     int save = errno;
153 
154     if (_res.options & RES_DEBUG) {
155         fprintf(file, "res_send: %s ([%s].%u): %s\n",
156             string,
157             inet_ntoa(address.sin_addr),
158             ntohs(address.sin_port),
159             strerror(error));
160     }
161     errno = save;
162 }
163 
164 
165 static void
Perror(FILE * file,char * string,int error)166 Perror(
167     FILE *file,
168     char *string,
169     int error
170     )
171 {
172     int save = errno;
173 
174     if (_res.options & RES_DEBUG) {
175         fprintf(file, "res_send: %s: %s\n",
176             string, strerror(error));
177     }
178     errno = save;
179 }
180 #endif
181 
182 void
res_send_setqhook(res_send_qhook hook)183 res_send_setqhook(
184     res_send_qhook hook
185     )
186 {
187 
188     Qhook = hook;
189 }
190 
191 void
res_send_setrhook(res_send_rhook hook)192 res_send_setrhook(
193     res_send_rhook hook
194     )
195 {
196 
197     Rhook = hook;
198 }
199 
200 /* int
201  * res_isourserver(ina)
202  *  looks up "ina" in _res.ns_addr_list[]
203  * returns:
204  *  0  : not found
205  *  >0 : found
206  * author:
207  *  paul vixie, 29may94
208  */
209 int
res_isourserver(const struct sockaddr_in * inp)210 res_isourserver(
211     const struct sockaddr_in *inp
212     )
213 {
214     struct sockaddr_in ina;
215     int ns, ret;
216 
217     ina = *inp;
218     ret = 0;
219     for (ns = 0;  ns < _res.nscount;  ns++) {
220         const struct sockaddr_in *srv = &_res.nsaddr_list[ns];
221 
222         if (srv->sin_family == ina.sin_family &&
223             srv->sin_port == ina.sin_port &&
224             (srv->sin_addr.s_addr == INADDR_ANY ||
225              srv->sin_addr.s_addr == ina.sin_addr.s_addr)) {
226             ret++;
227             break;
228         }
229     }
230     return (ret);
231 }
232 
233 /* int
234  * res_nameinquery(name, type, class, buf, eom)
235  *  look for (name,type,class) in the query section of packet (buf,eom)
236  * requires:
237  *  buf + HFIXEDSZ <= eom
238  * returns:
239  *  -1 : format error
240  *  0  : not found
241  *  >0 : found
242  * author:
243  *  paul vixie, 29may94
244  */
245 int
res_nameinquery(const char * name,int type,int class,const u_char * buf,const u_char * eom)246 res_nameinquery(
247     const char *name,
248     int type,
249     int class,
250     const u_char *buf,
251     const u_char *eom
252     )
253 {
254     const u_char *cp = buf + HFIXEDSZ;
255     int qdcount = ntohs(((HEADER*)buf)->qdcount);
256 
257     while (qdcount-- > 0) {
258         char tname[MAXDNAME+1];
259         int n, ttype, tclass;
260 
261         n = dn_expand(buf, eom, cp, tname, sizeof tname);
262         if (n < 0)
263             return (-1);
264         cp += n;
265         if (cp + 2 * INT16SZ > eom)
266             return (-1);
267         ttype = ns_get16(cp); cp += INT16SZ;
268         tclass = ns_get16(cp); cp += INT16SZ;
269         if (ttype == type &&
270             tclass == class &&
271             strcasecmp(tname, name) == 0)
272             return (1);
273     }
274     return (0);
275 }
276 
277 /* int
278  * res_queriesmatch(buf1, eom1, buf2, eom2)
279  *  is there a 1:1 mapping of (name,type,class)
280  *  in (buf1,eom1) and (buf2,eom2)?
281  * returns:
282  *  -1 : format error
283  *  0  : not a 1:1 mapping
284  *  >0 : is a 1:1 mapping
285  * author:
286  *  paul vixie, 29may94
287  */
288 int
res_queriesmatch(const u_char * buf1,const u_char * eom1,const u_char * buf2,const u_char * eom2)289 res_queriesmatch(
290     const u_char *buf1,
291     const u_char *eom1,
292     const u_char *buf2,
293     const u_char *eom2
294     )
295 {
296     const u_char *cp = buf1 + HFIXEDSZ;
297     int qdcount = ntohs(((HEADER*)buf1)->qdcount);
298 
299     if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
300         return (-1);
301 
302     /*
303      * Only header section present in replies to
304      * dynamic update packets.
305      */
306     if ( (((HEADER *)buf1)->opcode == ns_o_update) &&
307          (((HEADER *)buf2)->opcode == ns_o_update) )
308         return (1);
309 
310     if (qdcount != ntohs(((HEADER*)buf2)->qdcount))
311         return (0);
312     while (qdcount-- > 0) {
313         char tname[MAXDNAME+1];
314         int n, ttype, tclass;
315 
316         n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
317         if (n < 0)
318             return (-1);
319         cp += n;
320         if (cp + 2 * INT16SZ > eom1)
321             return (-1);
322         ttype = ns_get16(cp);   cp += INT16SZ;
323         tclass = ns_get16(cp); cp += INT16SZ;
324         if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
325             return (0);
326     }
327     return (1);
328 }
329 
330 int
res_send(const u_char * buf,int buflen,u_char * ans,int anssiz)331 res_send(
332     const u_char *buf,
333     int buflen,
334     u_char *ans,
335     int anssiz
336     )
337 {
338     HEADER *hp = (HEADER *) buf;
339     HEADER *anhp = (HEADER *) ans;
340     int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns;
341     ssize_t n;
342     u_int32_t badns;    /* XXX NSMAX can't exceed #/bits in this variable */
343 
344     if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
345         /* errno should have been set by res_init() in this case. */
346         return (-1);
347     }
348     if (anssiz < HFIXEDSZ) {
349         errno = EINVAL;
350         return (-1);
351     }
352     DprintQ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY),
353         (stdout, ";; res_send()\n"), buf, buflen);
354     v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
355     gotsomewhere = 0;
356     connreset = 0;
357     terrno = ETIMEDOUT;
358     badns = 0;
359 
360     /*
361      * Send request, RETRY times, or until successful
362      */
363     for (try = 0; try < _res.retry; try++) {
364         for (ns = 0; ns < _res.nscount; ns++) {
365         struct sockaddr_in *nsap = &_res.nsaddr_list[ns];
366     same_ns:
367         if (badns & (1 << ns)) {
368             res_close();
369             goto next_ns;
370         }
371 
372         if (Qhook) {
373             int done = 0, loops = 0;
374 
375             do {
376                 res_sendhookact act;
377 
378                 act = (*Qhook)(&nsap, &buf, &buflen,
379                            ans, anssiz, &resplen);
380                 switch (act) {
381                 case res_goahead:
382                     done = 1;
383                     break;
384                 case res_nextns:
385                     res_close();
386                     goto next_ns;
387                 case res_done:
388                     return (resplen);
389                 case res_modified:
390                     /* give the hook another try */
391                     if (++loops < 42) /*doug adams*/
392                         break;
393                     /*FALLTHROUGH*/
394                 case res_error:
395                     /*FALLTHROUGH*/
396                 default:
397                     return (-1);
398                 }
399             } while (!done);
400         }
401 
402         Dprint(_res.options & RES_DEBUG,
403                (stdout, ";; Querying server (# %d) address = %s\n",
404             ns + 1, inet_ntoa(nsap->sin_addr)));
405 
406         if (v_circuit) {
407             int truncated;
408             struct iovec iov[2];
409             u_short len;
410             u_char *cp;
411 
412             /*
413              * Use virtual circuit;
414              * at most one attempt per server.
415              */
416             try = _res.retry;
417             truncated = 0;
418             if (s < 0 || !vc || hp->opcode == ns_o_update) {
419                 if (s >= 0)
420                     res_close();
421 
422                 s = socket(PF_INET, SOCK_STREAM, 0);
423                 if (s < 0) {
424                     terrno = errno;
425                     Perror(stderr, "socket(vc)", errno);
426                     return (-1);
427                 }
428                 errno = 0;
429                 nsap->sin_len = sizeof ( *nsap );
430                 if (connect(s, (struct sockaddr *)nsap,
431                         sizeof *nsap) < 0) {
432                     terrno = errno;
433                     Aerror(stderr, "connect/vc",
434                            errno, *nsap);
435                     badns |= (1 << ns);
436                     res_close();
437                     goto next_ns;
438                 }
439                 vc = 1;
440             }
441             /*
442              * Send length & message
443              */
444             putshort((u_short)buflen, (u_char*)&len);
445             iov[0].iov_base = (caddr_t)&len;
446             iov[0].iov_len = INT16SZ;
447             iov[1].iov_base = (caddr_t)buf;
448             iov[1].iov_len = buflen;
449             if (writev(s, iov, 2) != (INT16SZ + buflen)) {
450                 terrno = errno;
451                 Perror(stderr, "write failed", errno);
452                 badns |= (1 << ns);
453                 res_close();
454                 goto next_ns;
455             }
456             /*
457              * Receive length & response
458              */
459 read_len:
460             cp = ans;
461             len = INT16SZ;
462             while ((n = read(s, (char *)cp, (int)len)) > 0) {
463                 cp += n;
464                 len = (u_short)( len - n );
465                 if (len <= 0)
466                     break;
467             }
468             if (n <= 0) {
469                 terrno = errno;
470                 Perror(stderr, "read failed", errno);
471                 res_close();
472                 /*
473                  * A long running process might get its TCP
474                  * connection reset if the remote server was
475                  * restarted.  Requery the server instead of
476                  * trying a new one.  When there is only one
477                  * server, this means that a query might work
478                  * instead of failing.  We only allow one reset
479                  * per query to prevent looping.
480                  */
481                 if (terrno == ECONNRESET && !connreset) {
482                     connreset = 1;
483                     res_close();
484                     goto same_ns;
485                 }
486                 res_close();
487                 goto next_ns;
488             }
489             resplen = ns_get16(ans);
490             if (resplen > anssiz) {
491                 Dprint(_res.options & RES_DEBUG,
492                        (stdout, ";; response truncated\n")
493                        );
494                 truncated = 1;
495                 len = (ushort)anssiz;
496             } else
497                 len = (ushort)resplen;
498             if (len < HFIXEDSZ) {
499                 /*
500                  * Undersized message.
501                  */
502                 Dprint(_res.options & RES_DEBUG,
503                        (stdout, ";; undersized: %d\n", len));
504                 terrno = EMSGSIZE;
505                 badns |= (1 << ns);
506                 res_close();
507                 goto next_ns;
508             }
509             cp = ans;
510             while (len != 0 &&
511                    (n = read(s, (char *)cp, (int)len)) > 0) {
512                 cp += n;
513                 len = (u_short)( len - n );
514             }
515             if (n <= 0) {
516                 terrno = errno;
517                 Perror(stderr, "read(vc)", errno);
518                 res_close();
519                 goto next_ns;
520             }
521             if (truncated) {
522                 /*
523                  * Flush rest of answer
524                  * so connection stays in synch.
525                  */
526                 anhp->tc = 1;
527                 len = (ushort)( resplen - anssiz );
528                 while (len != 0) {
529                     char junk[PACKETSZ];
530 
531                     n = (len > sizeof(junk)
532                          ? sizeof(junk)
533                          : len);
534                     if ((n = read(s, junk, n)) > 0)
535                         len = (u_short)( len - n );
536                     else
537                         break;
538                 }
539             }
540             /*
541              * The calling applicating has bailed out of
542              * a previous call and failed to arrange to have
543              * the circuit closed or the server has got
544              * itself confused. Anyway drop the packet and
545              * wait for the correct one.
546              */
547             if (hp->id != anhp->id) {
548                 DprintQ((_res.options & RES_DEBUG) ||
549                     (_res.pfcode & RES_PRF_REPLY),
550                     (stdout, ";; old answer (unexpected):\n"),
551                     ans, (resplen>anssiz)?anssiz:resplen);
552                 goto read_len;
553             }
554         } else {
555             /*
556              * Use datagrams.
557              */
558 #ifndef NOPOLL
559             struct pollfd pfd;
560             int msec;
561 #endif
562             struct timeval timeout;
563             fd_set dsmask, *dsmaskp;
564             int dsmasklen;
565             struct sockaddr_in from;
566             int fromlen;
567 
568             if ((s < 0) || vc) {
569                 if (vc)
570                     res_close();
571                 s = socket(PF_INET, SOCK_DGRAM, 0);
572                 if (s < 0) {
573 #ifndef CAN_RECONNECT
574  bad_dg_sock:
575 #endif
576                     terrno = errno;
577                     Perror(stderr, "socket(dg)", errno);
578                     return (-1);
579                 }
580                 connected = 0;
581             }
582 #ifndef CANNOT_CONNECT_DGRAM
583             /*
584              * On a 4.3BSD+ machine (client and server,
585              * actually), sending to a nameserver datagram
586              * port with no nameserver will cause an
587              * ICMP port unreachable message to be returned.
588              * If our datagram socket is "connected" to the
589              * server, we get an ECONNREFUSED error on the next
590              * socket operation, and select returns if the
591              * error message is received.  We can thus detect
592              * the absence of a nameserver without timing out.
593              * If we have sent queries to at least two servers,
594              * however, we don't want to remain connected,
595              * as we wish to receive answers from the first
596              * server to respond.
597              */
598             if (_res.nscount == 1 || (try == 0 && ns == 0)) {
599                 /*
600                  * Connect only if we are sure we won't
601                  * receive a response from another server.
602                  */
603                 if (!connected) {
604                     nsap->sin_len = sizeof ( *nsap );
605                     if (connect(s, (struct sockaddr *)nsap,
606                             sizeof *nsap
607                             ) < 0) {
608                         Aerror(stderr,
609                                "connect(dg)",
610                                errno, *nsap);
611                         badns |= (1 << ns);
612                         res_close();
613                         goto next_ns;
614                     }
615                     connected = 1;
616                 }
617                 if (send(s, (char*)buf, buflen, 0) != buflen) {
618                     Perror(stderr, "send", errno);
619                     badns |= (1 << ns);
620                     res_close();
621                     goto next_ns;
622                 }
623             } else {
624                 /*
625                  * Disconnect if we want to listen
626                  * for responses from more than one server.
627                  */
628                 if (connected) {
629 #ifdef CAN_RECONNECT
630                     struct sockaddr_in no_addr;
631 
632                     no_addr.sin_family = AF_INET;
633                     no_addr.sin_addr.s_addr = INADDR_ANY;
634                     no_addr.sin_port = 0;
635                     (void) connect(s,
636                                (struct sockaddr *)
637                                 &no_addr,
638                                sizeof no_addr);
639 #else
640                     int s1 = socket(PF_INET, SOCK_DGRAM,0);
641                     if (s1 < 0)
642                         goto bad_dg_sock;
643                     (void) dup2(s1, s);
644                     (void) close(s1);
645                     Dprint(_res.options & RES_DEBUG,
646                         (stdout, ";; new DG socket\n"))
647 #endif /* CAN_RECONNECT */
648                     connected = 0;
649                     errno = 0;
650                 }
651 #endif /* !CANNOT_CONNECT_DGRAM */
652                 if (sendto(s, (char*)buf, buflen, 0,
653                        (struct sockaddr *)nsap,
654                        sizeof *nsap)
655                     != buflen) {
656                     Aerror(stderr, "sendto", errno, *nsap);
657                     badns |= (1 << ns);
658                     res_close();
659                     goto next_ns;
660                 }
661 #ifndef CANNOT_CONNECT_DGRAM
662             }
663 #endif /* !CANNOT_CONNECT_DGRAM */
664 
665             /*
666              * Wait for reply
667              */
668 #ifndef NOPOLL
669     othersyscall:
670             if (use_poll) {
671                 msec = (_res.retrans << try) * 1000;
672                 if (try > 0)
673                     msec /= _res.nscount;
674                 if (msec <= 0)
675                     msec = 1000;
676             } else {
677 #endif
678                 timeout.tv_sec = (_res.retrans << try);
679                 if (try > 0)
680                     timeout.tv_sec /= _res.nscount;
681                 if ((long) timeout.tv_sec <= 0)
682                     timeout.tv_sec = 1;
683                 timeout.tv_usec = 0;
684 #ifndef NOPOLL
685             }
686 #endif
687     wait:
688             if (s < 0) {
689                 Perror(stderr, "s out-of-bounds", EMFILE);
690                 res_close();
691                 goto next_ns;
692             }
693 #ifndef NOPOLL
694             if (use_poll) {
695                 struct sigaction sa, osa;
696                 int sigsys_installed = 0;
697 
698                 pfd.fd = s;
699                 pfd.events = POLLIN;
700                 if (use_poll == 1) {
701                     bzero(&sa, sizeof(sa));
702                     sa.sa_handler = SIG_IGN;
703                     if (sigaction(SIGSYS, &sa, &osa) >= 0)
704                         sigsys_installed = 1;
705                 }
706                 n = poll(&pfd, 1, msec);
707                 if (sigsys_installed == 1) {
708                     int oerrno = errno;
709                     sigaction(SIGSYS, &osa, NULL);
710                     errno = oerrno;
711                 }
712                 /* XXX why does nosys() return EINVAL? */
713                 if (n < 0 && (errno == ENOSYS ||
714                     errno == EINVAL)) {
715                     use_poll = 0;
716                     goto othersyscall;
717                 } else if (use_poll == 1)
718                     use_poll = 2;
719                 if (n < 0) {
720                     if (errno == EINTR)
721                         goto wait;
722                     Perror(stderr, "poll", errno);
723                     res_close();
724                     goto next_ns;
725                 }
726             } else {
727 #endif
728                 dsmasklen = howmany(s + 1, NFDBITS) *
729                         sizeof(fd_mask);
730                 if (dsmasklen > sizeof(fd_set)) {
731                     dsmaskp = (fd_set *)malloc(dsmasklen);
732                     if (dsmaskp == NULL) {
733                         res_close();
734                         goto next_ns;
735                     }
736                 } else
737                     dsmaskp = &dsmask;
738                 /* only zero what we need */
739                 memset((char *)dsmaskp, 0, dsmasklen);
740                 FD_SET(s, dsmaskp);
741                 n = select(s + 1, dsmaskp, (fd_set *)NULL,
742                        (fd_set *)NULL, &timeout);
743                 if (dsmaskp != &dsmask)
744                     free(dsmaskp);
745                 if (n < 0) {
746                     if (errno == EINTR)
747                         goto wait;
748                     Perror(stderr, "select", errno);
749                     res_close();
750                     goto next_ns;
751                 }
752 #ifndef NOPOLL
753             }
754 #endif
755 
756             if (n == 0) {
757                 /*
758                  * timeout
759                  */
760                 Dprint(_res.options & RES_DEBUG,
761                        (stdout, ";; timeout\n"));
762                 gotsomewhere = 1;
763                 res_close();
764                 goto next_ns;
765             }
766             errno = 0;
767             fromlen = sizeof(struct sockaddr_in);
768             resplen = (int)recvfrom(s, (char*)ans, anssiz, 0,
769                        (struct sockaddr *)&from, (socklen_t *)&fromlen);
770             if (resplen <= 0) {
771                 Perror(stderr, "recvfrom", errno);
772                 res_close();
773                 goto next_ns;
774             }
775             gotsomewhere = 1;
776             if (resplen < HFIXEDSZ) {
777                 /*
778                  * Undersized message.
779                  */
780                 Dprint(_res.options & RES_DEBUG,
781                        (stdout, ";; undersized: %d\n",
782                     resplen));
783                 terrno = EMSGSIZE;
784                 badns |= (1 << ns);
785                 res_close();
786                 goto next_ns;
787             }
788             if (hp->id != anhp->id) {
789                 /*
790                  * response from old query, ignore it.
791                  * XXX - potential security hazard could
792                  *   be detected here.
793                  */
794                 DprintQ((_res.options & RES_DEBUG) ||
795                     (_res.pfcode & RES_PRF_REPLY),
796                     (stdout, ";; old answer:\n"),
797                     ans, (resplen>anssiz)?anssiz:resplen);
798                 goto wait;
799             }
800 #ifdef CHECK_SRVR_ADDR
801             if (!(_res.options & RES_INSECURE1) &&
802                 !res_isourserver(&from)) {
803                 /*
804                  * response from wrong server? ignore it.
805                  * XXX - potential security hazard could
806                  *   be detected here.
807                  */
808                 DprintQ((_res.options & RES_DEBUG) ||
809                     (_res.pfcode & RES_PRF_REPLY),
810                     (stdout, ";; not our server:\n"),
811                     ans, (resplen>anssiz)?anssiz:resplen);
812                 goto wait;
813             }
814 #endif
815             if (!(_res.options & RES_INSECURE2) &&
816                 !res_queriesmatch(buf, buf + buflen,
817                           ans, ans + anssiz)) {
818                 /*
819                  * response contains wrong query? ignore it.
820                  * XXX - potential security hazard could
821                  *   be detected here.
822                  */
823                 DprintQ((_res.options & RES_DEBUG) ||
824                     (_res.pfcode & RES_PRF_REPLY),
825                     (stdout, ";; wrong query name:\n"),
826                     ans, (resplen>anssiz)?anssiz:resplen);
827                 goto wait;
828             }
829             if (anhp->rcode == SERVFAIL ||
830                 anhp->rcode == NOTIMP ||
831                 anhp->rcode == REFUSED) {
832                 DprintQ(_res.options & RES_DEBUG,
833                     (stdout, "server rejected query:\n"),
834                     ans, (resplen>anssiz)?anssiz:resplen);
835                 badns |= (1 << ns);
836                 res_close();
837                 /* don't retry if called from dig */
838                 if (!_res.pfcode)
839                     goto next_ns;
840             }
841             if (!(_res.options & RES_IGNTC) && anhp->tc) {
842                 /*
843                  * get rest of answer;
844                  * use TCP with same server.
845                  */
846                 Dprint(_res.options & RES_DEBUG,
847                        (stdout, ";; truncated answer\n"));
848                 v_circuit = 1;
849                 res_close();
850                 goto same_ns;
851             }
852         } /*if vc/dg*/
853         Dprint((_res.options & RES_DEBUG) ||
854                ((_res.pfcode & RES_PRF_REPLY) &&
855             (_res.pfcode & RES_PRF_HEAD1)),
856                (stdout, ";; got answer:\n"));
857         if((_res.options & RES_DEBUG) ||
858             (_res.pfcode & RES_PRF_REPLY)) {
859             __fp_nquery(ans, (resplen>anssiz)?anssiz:resplen, stdout);
860         }
861         /*
862          * If using virtual circuits, we assume that the first server
863          * is preferred over the rest (i.e. it is on the local
864          * machine) and only keep that one open.
865          * If we have temporarily opened a virtual circuit,
866          * or if we haven't been asked to keep a socket open,
867          * close the socket.
868          */
869         if ((v_circuit && (!(_res.options & RES_USEVC) || ns != 0)) ||
870             !(_res.options & RES_STAYOPEN)) {
871             res_close();
872         }
873         if (Rhook) {
874             int done = 0, loops = 0;
875 
876             do {
877                 res_sendhookact act;
878 
879                 act = (*Rhook)(nsap, buf, buflen,
880                            ans, anssiz, &resplen);
881                 switch (act) {
882                 case res_goahead:
883                 case res_done:
884                     done = 1;
885                     break;
886                 case res_nextns:
887                     res_close();
888                     goto next_ns;
889                 case res_modified:
890                     /* give the hook another try */
891                     if (++loops < 42) /*doug adams*/
892                         break;
893                     /*FALLTHROUGH*/
894                 case res_error:
895                     /*FALLTHROUGH*/
896                 default:
897                     return (-1);
898                 }
899             } while (!done);
900 
901         }
902         return (resplen);
903     next_ns: ;
904        } /*foreach ns*/
905     } /*foreach retry*/
906     res_close();
907     if (!v_circuit) {
908         if (!gotsomewhere)
909             errno = ECONNREFUSED;   /* no nameservers found */
910         else
911             errno = ETIMEDOUT;  /* no answer obtained */
912     } else
913         errno = terrno;
914     return (-1);
915 }
916 
917 /*
918  * This routine is for closing the socket if a virtual circuit is used and
919  * the program wants to close it.  This provides support for endhostent()
920  * which expects to close the socket.
921  *
922  * This routine is not expected to be user visible.
923  */
924 void
res_close()925 res_close()
926 {
927     if (s >= 0) {
928         (void) close(s);
929         s = -1;
930         connected = 0;
931         vc = 0;
932     }
933 }
934