Back to index

glibc  2.9
res_send.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1985, 1989, 1993
00003  *    The Regents of the University of California.  All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 4. Neither the name of the University nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 
00030 /*
00031  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
00032  *
00033  * Permission to use, copy, modify, and distribute this software for any
00034  * purpose with or without fee is hereby granted, provided that the above
00035  * copyright notice and this permission notice appear in all copies, and that
00036  * the name of Digital Equipment Corporation not be used in advertising or
00037  * publicity pertaining to distribution of the document or software without
00038  * specific, written prior permission.
00039  *
00040  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
00041  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
00042  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
00043  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
00044  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
00045  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
00046  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00047  * SOFTWARE.
00048  */
00049 
00050 /*
00051  * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
00052  *
00053  * Permission to use, copy, modify, and distribute this software for any
00054  * purpose with or without fee is hereby granted, provided that the above
00055  * copyright notice and this permission notice appear in all copies.
00056  *
00057  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
00058  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
00059  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
00060  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
00061  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
00062  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
00063  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00064  * SOFTWARE.
00065  */
00066 
00067 #if defined(LIBC_SCCS) && !defined(lint)
00068 static const char sccsid[] = "@(#)res_send.c     8.1 (Berkeley) 6/4/93";
00069 static const char rcsid[] = "$BINDId: res_send.c,v 8.38 2000/03/30 20:16:51 vixie Exp $";
00070 #endif /* LIBC_SCCS and not lint */
00071 
00072 /*
00073  * Send query to name server and wait for reply.
00074  */
00075 
00076 #include <assert.h>
00077 #include <sys/types.h>
00078 #include <sys/param.h>
00079 #include <sys/time.h>
00080 #include <sys/socket.h>
00081 #include <sys/uio.h>
00082 #include <sys/poll.h>
00083 
00084 #include <netinet/in.h>
00085 #include <arpa/nameser.h>
00086 #include <arpa/inet.h>
00087 #include <sys/ioctl.h>
00088 
00089 #include <errno.h>
00090 #include <fcntl.h>
00091 #include <netdb.h>
00092 #include <resolv.h>
00093 #include <signal.h>
00094 #include <stdio.h>
00095 #include <stdlib.h>
00096 #include <string.h>
00097 #include <unistd.h>
00098 
00099 #if PACKETSZ > 65536
00100 #define MAXPACKET       PACKETSZ
00101 #else
00102 #define MAXPACKET       65536
00103 #endif
00104 
00105 
00106 /* From ev_streams.c.  */
00107 
00108 static inline void
00109 __attribute ((always_inline))
00110 evConsIovec(void *buf, size_t cnt, struct iovec *vec) {
00111        memset(vec, 0xf5, sizeof (*vec));
00112        vec->iov_base = buf;
00113        vec->iov_len = cnt;
00114 }
00115 
00116 /* From ev_timers.c.  */
00117 
00118 #define BILLION 1000000000
00119 
00120 static inline void
00121 evConsTime(struct timespec *res, time_t sec, long nsec) {
00122        res->tv_sec = sec;
00123        res->tv_nsec = nsec;
00124 }
00125 
00126 static inline void
00127 evAddTime(struct timespec *res, const struct timespec *addend1,
00128          const struct timespec *addend2) {
00129        res->tv_sec = addend1->tv_sec + addend2->tv_sec;
00130        res->tv_nsec = addend1->tv_nsec + addend2->tv_nsec;
00131        if (res->tv_nsec >= BILLION) {
00132               res->tv_sec++;
00133               res->tv_nsec -= BILLION;
00134        }
00135 }
00136 
00137 static inline void
00138 evSubTime(struct timespec *res, const struct timespec *minuend,
00139          const struct timespec *subtrahend) {
00140        res->tv_sec = minuend->tv_sec - subtrahend->tv_sec;
00141        if (minuend->tv_nsec >= subtrahend->tv_nsec)
00142               res->tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec;
00143        else {
00144               res->tv_nsec = (BILLION
00145                             - subtrahend->tv_nsec + minuend->tv_nsec);
00146               res->tv_sec--;
00147        }
00148 }
00149 
00150 static inline int
00151 evCmpTime(struct timespec a, struct timespec b) {
00152        long x = a.tv_sec - b.tv_sec;
00153 
00154        if (x == 0L)
00155               x = a.tv_nsec - b.tv_nsec;
00156        return (x < 0L ? (-1) : x > 0L ? (1) : (0));
00157 }
00158 
00159 static inline void
00160 evNowTime(struct timespec *res) {
00161        struct timeval now;
00162 
00163        if (gettimeofday(&now, NULL) < 0)
00164               evConsTime(res, 0, 0);
00165        else
00166               TIMEVAL_TO_TIMESPEC (&now, res);
00167 }
00168 
00169 
00170 /* Options.  Leave them on. */
00171 /* #undef DEBUG */
00172 #include "res_debug.h"
00173 
00174 #define EXT(res) ((res)->_u._ext)
00175 
00176 /* Forward. */
00177 
00178 static int           send_vc(res_state, const u_char *, int,
00179                             const u_char *, int,
00180                             u_char **, int *, int *, int, u_char **,
00181                             u_char **, int *, int *);
00182 static int           send_dg(res_state, const u_char *, int,
00183                             const u_char *, int,
00184                             u_char **, int *, int *, int,
00185                             int *, int *, u_char **,
00186                             u_char **, int *, int *);
00187 #ifdef DEBUG
00188 static void          Aerror(const res_state, FILE *, const char *, int,
00189                             const struct sockaddr *);
00190 static void          Perror(const res_state, FILE *, const char *, int);
00191 #endif
00192 static int           sock_eq(struct sockaddr_in6 *, struct sockaddr_in6 *);
00193 
00194 /* Reachover. */
00195 
00196 static void convaddr4to6(struct sockaddr_in6 *sa);
00197 
00198 /* Public. */
00199 
00200 /* int
00201  * res_isourserver(ina)
00202  *     looks up "ina" in _res.ns_addr_list[]
00203  * returns:
00204  *     0  : not found
00205  *     >0 : found
00206  * author:
00207  *     paul vixie, 29may94
00208  */
00209 int
00210 res_ourserver_p(const res_state statp, const struct sockaddr_in6 *inp)
00211 {
00212        int ns;
00213 
00214         if (inp->sin6_family == AF_INET) {
00215             struct sockaddr_in *in4p = (struct sockaddr_in *) inp;
00216            in_port_t port = in4p->sin_port;
00217            in_addr_t addr = in4p->sin_addr.s_addr;
00218 
00219             for (ns = 0;  ns < MAXNS;  ns++) {
00220                 const struct sockaddr_in *srv =
00221                   (struct sockaddr_in *)EXT(statp).nsaddrs[ns];
00222 
00223                 if ((srv != NULL) && (srv->sin_family == AF_INET) &&
00224                     (srv->sin_port == port) &&
00225                     (srv->sin_addr.s_addr == INADDR_ANY ||
00226                      srv->sin_addr.s_addr == addr))
00227                     return (1);
00228             }
00229         } else if (inp->sin6_family == AF_INET6) {
00230             for (ns = 0;  ns < MAXNS;  ns++) {
00231                 const struct sockaddr_in6 *srv = EXT(statp).nsaddrs[ns];
00232                 if ((srv != NULL) && (srv->sin6_family == AF_INET6) &&
00233                     (srv->sin6_port == inp->sin6_port) &&
00234                     !(memcmp(&srv->sin6_addr, &in6addr_any,
00235                              sizeof (struct in6_addr)) &&
00236                       memcmp(&srv->sin6_addr, &inp->sin6_addr,
00237                              sizeof (struct in6_addr))))
00238                     return (1);
00239             }
00240         }
00241        return (0);
00242 }
00243 
00244 /* int
00245  * res_nameinquery(name, type, class, buf, eom)
00246  *     look for (name,type,class) in the query section of packet (buf,eom)
00247  * requires:
00248  *     buf + HFIXEDSZ <= eom
00249  * returns:
00250  *     -1 : format error
00251  *     0  : not found
00252  *     >0 : found
00253  * author:
00254  *     paul vixie, 29may94
00255  */
00256 int
00257 res_nameinquery(const char *name, int type, int class,
00258               const u_char *buf, const u_char *eom)
00259 {
00260        const u_char *cp = buf + HFIXEDSZ;
00261        int qdcount = ntohs(((HEADER*)buf)->qdcount);
00262 
00263        while (qdcount-- > 0) {
00264               char tname[MAXDNAME+1];
00265               int n, ttype, tclass;
00266 
00267               n = dn_expand(buf, eom, cp, tname, sizeof tname);
00268               if (n < 0)
00269                      return (-1);
00270               cp += n;
00271               if (cp + 2 * INT16SZ > eom)
00272                      return (-1);
00273               NS_GET16(ttype, cp);
00274               NS_GET16(tclass, cp);
00275               if (ttype == type && tclass == class &&
00276                   ns_samename(tname, name) == 1)
00277                      return (1);
00278        }
00279        return (0);
00280 }
00281 libresolv_hidden_def (res_nameinquery)
00282 
00283 /* int
00284  * res_queriesmatch(buf1, eom1, buf2, eom2)
00285  *     is there a 1:1 mapping of (name,type,class)
00286  *     in (buf1,eom1) and (buf2,eom2)?
00287  * returns:
00288  *     -1 : format error
00289  *     0  : not a 1:1 mapping
00290  *     >0 : is a 1:1 mapping
00291  * author:
00292  *     paul vixie, 29may94
00293  */
00294 int
00295 res_queriesmatch(const u_char *buf1, const u_char *eom1,
00296                const u_char *buf2, const u_char *eom2)
00297 {
00298        if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
00299               return (-1);
00300 
00301        /*
00302         * Only header section present in replies to
00303         * dynamic update packets.
00304         */
00305        if ((((HEADER *)buf1)->opcode == ns_o_update) &&
00306            (((HEADER *)buf2)->opcode == ns_o_update))
00307               return (1);
00308 
00309        /* Note that we initially do not convert QDCOUNT to the host byte
00310           order.  We can compare it with the second buffer's QDCOUNT
00311           value without doing this.  */
00312        int qdcount = ((HEADER*)buf1)->qdcount;
00313        if (qdcount != ((HEADER*)buf2)->qdcount)
00314               return (0);
00315 
00316        qdcount = htons (qdcount);
00317        const u_char *cp = buf1 + HFIXEDSZ;
00318 
00319        while (qdcount-- > 0) {
00320               char tname[MAXDNAME+1];
00321               int n, ttype, tclass;
00322 
00323               n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
00324               if (n < 0)
00325                      return (-1);
00326               cp += n;
00327               if (cp + 2 * INT16SZ > eom1)
00328                      return (-1);
00329               NS_GET16(ttype, cp);
00330               NS_GET16(tclass, cp);
00331               if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
00332                      return (0);
00333        }
00334        return (1);
00335 }
00336 libresolv_hidden_def (res_queriesmatch)
00337 
00338 int
00339 __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
00340                const u_char *buf2, int buflen2,
00341                u_char *ans, int anssiz, u_char **ansp, u_char **ansp2,
00342                int *nansp2, int *resplen2)
00343 {
00344   int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
00345 
00346        if (statp->nscount == 0) {
00347               __set_errno (ESRCH);
00348               return (-1);
00349        }
00350 
00351        if (anssiz < (buf2 == NULL ? 1 : 2) * HFIXEDSZ) {
00352               __set_errno (EINVAL);
00353               return (-1);
00354        }
00355 
00356 #ifdef USE_HOOKS
00357        if (__builtin_expect (statp->qhook || statp->rhook, 0)) {
00358               if (anssiz < MAXPACKET && ansp) {
00359                      u_char *buf = malloc (MAXPACKET);
00360                      if (buf == NULL)
00361                             return (-1);
00362                      memcpy (buf, ans, HFIXEDSZ);
00363                      *ansp = buf;
00364                      ans = buf;
00365                      anssiz = MAXPACKET;
00366               }
00367        }
00368 #endif
00369 
00370        DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
00371               (stdout, ";; res_send()\n"), buf, buflen);
00372        v_circuit = ((statp->options & RES_USEVC)
00373                    || buflen > PACKETSZ
00374                    || buflen2 > PACKETSZ);
00375        gotsomewhere = 0;
00376        terrno = ETIMEDOUT;
00377 
00378        /*
00379         * If the ns_addr_list in the resolver context has changed, then
00380         * invalidate our cached copy and the associated timing data.
00381         */
00382        if (EXT(statp).nsinit) {
00383               int needclose = 0;
00384 
00385               if (EXT(statp).nscount != statp->nscount)
00386                      needclose++;
00387               else
00388                      for (ns = 0; ns < MAXNS; ns++) {
00389                             unsigned int map = EXT(statp).nsmap[ns];
00390                             if (map < MAXNS
00391                                 && !sock_eq((struct sockaddr_in6 *)
00392                                           &statp->nsaddr_list[map],
00393                                           EXT(statp).nsaddrs[ns]))
00394                             {
00395                                    needclose++;
00396                                    break;
00397                             }
00398                      }
00399               if (needclose)
00400                      __res_iclose(statp, false);
00401        }
00402 
00403        /*
00404         * Maybe initialize our private copy of the ns_addr_list.
00405         */
00406        if (EXT(statp).nsinit == 0) {
00407               unsigned char map[MAXNS];
00408 
00409               memset (map, MAXNS, sizeof (map));
00410               for (n = 0; n < MAXNS; n++) {
00411                      ns = EXT(statp).nsmap[n];
00412                      if (ns < statp->nscount)
00413                             map[ns] = n;
00414                      else if (ns < MAXNS) {
00415                             free(EXT(statp).nsaddrs[n]);
00416                             EXT(statp).nsaddrs[n] = NULL;
00417                             EXT(statp).nsmap[n] = MAXNS;
00418                      }
00419               }
00420               n = statp->nscount;
00421               if (statp->nscount > EXT(statp).nscount)
00422                      for (n = EXT(statp).nscount, ns = 0;
00423                           n < statp->nscount; n++) {
00424                             while (ns < MAXNS
00425                                    && EXT(statp).nsmap[ns] != MAXNS)
00426                                    ns++;
00427                             if (ns == MAXNS)
00428                                    break;
00429                             EXT(statp).nsmap[ns] = n;
00430                             map[n] = ns++;
00431                      }
00432               EXT(statp).nscount = n;
00433               for (ns = 0; ns < EXT(statp).nscount; ns++) {
00434                      n = map[ns];
00435                      if (EXT(statp).nsaddrs[n] == NULL)
00436                             EXT(statp).nsaddrs[n] =
00437                                 malloc(sizeof (struct sockaddr_in6));
00438                      if (EXT(statp).nsaddrs[n] != NULL) {
00439                             memset (mempcpy(EXT(statp).nsaddrs[n],
00440                                           &statp->nsaddr_list[ns],
00441                                           sizeof (struct sockaddr_in)),
00442                                    '\0',
00443                                    sizeof (struct sockaddr_in6)
00444                                    - sizeof (struct sockaddr_in));
00445                             EXT(statp).nssocks[n] = -1;
00446                             n++;
00447                      }
00448               }
00449               EXT(statp).nsinit = 1;
00450        }
00451 
00452        /*
00453         * Some resolvers want to even out the load on their nameservers.
00454         * Note that RES_BLAST overrides RES_ROTATE.
00455         */
00456        if (__builtin_expect ((statp->options & RES_ROTATE) != 0, 0) &&
00457            (statp->options & RES_BLAST) == 0) {
00458               struct sockaddr_in6 *ina;
00459               unsigned int map;
00460 
00461               n = 0;
00462               while (n < MAXNS && EXT(statp).nsmap[n] == MAXNS)
00463                      n++;
00464               if (n < MAXNS) {
00465                      ina = EXT(statp).nsaddrs[n];
00466                      map = EXT(statp).nsmap[n];
00467                      for (;;) {
00468                             ns = n + 1;
00469                             while (ns < MAXNS
00470                                    && EXT(statp).nsmap[ns] == MAXNS)
00471                                    ns++;
00472                             if (ns == MAXNS)
00473                                    break;
00474                             EXT(statp).nsaddrs[n] = EXT(statp).nsaddrs[ns];
00475                             EXT(statp).nsmap[n] = EXT(statp).nsmap[ns];
00476                             n = ns;
00477                      }
00478                      EXT(statp).nsaddrs[n] = ina;
00479                      EXT(statp).nsmap[n] = map;
00480               }
00481        }
00482 
00483        /*
00484         * Send request, RETRY times, or until successful.
00485         */
00486        for (try = 0; try < statp->retry; try++) {
00487            for (ns = 0; ns < MAXNS; ns++)
00488            {
00489               struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
00490 
00491               if (nsap == NULL)
00492                      goto next_ns;
00493            same_ns:
00494 #ifdef USE_HOOKS
00495               if (__builtin_expect (statp->qhook != NULL, 0)) {
00496                      int done = 0, loops = 0;
00497 
00498                      do {
00499                             res_sendhookact act;
00500 
00501                             struct sockaddr_in *nsap4;
00502                             nsap4 = (struct sockaddr_in *) nsap;
00503                             act = (*statp->qhook)(&nsap4, &buf, &buflen,
00504                                                 ans, anssiz, &resplen);
00505                             nsap = (struct sockaddr_in6 *) nsap4;
00506                             switch (act) {
00507                             case res_goahead:
00508                                    done = 1;
00509                                    break;
00510                             case res_nextns:
00511                                    __res_iclose(statp, false);
00512                                    goto next_ns;
00513                             case res_done:
00514                                    return (resplen);
00515                             case res_modified:
00516                                    /* give the hook another try */
00517                                    if (++loops < 42) /*doug adams*/
00518                                           break;
00519                                    /*FALLTHROUGH*/
00520                             case res_error:
00521                                    /*FALLTHROUGH*/
00522                             default:
00523                                    return (-1);
00524                             }
00525                      } while (!done);
00526               }
00527 #endif
00528 
00529 #ifdef DEBUG
00530               char tmpbuf[40];
00531 #endif
00532               Dprint(statp->options & RES_DEBUG,
00533                      (stdout, ";; Querying server (# %d) address = %s\n",
00534                      ns + 1, inet_ntop(AF_INET6, &nsap->sin6_addr,
00535                                      tmpbuf, sizeof (tmpbuf))));
00536 
00537               if (__builtin_expect (v_circuit, 0)) {
00538                      /* Use VC; at most one attempt per server. */
00539                      try = statp->retry;
00540                      n = send_vc(statp, buf, buflen, buf2, buflen2,
00541                                 &ans, &anssiz, &terrno,
00542                                 ns, ansp, ansp2, nansp2, resplen2);
00543                      if (n < 0)
00544                             return (-1);
00545                      if (n == 0)
00546                             goto next_ns;
00547               } else {
00548                      /* Use datagrams. */
00549                      n = send_dg(statp, buf, buflen, buf2, buflen2,
00550                                 &ans, &anssiz, &terrno,
00551                                 ns, &v_circuit, &gotsomewhere, ansp,
00552                                 ansp2, nansp2, resplen2);
00553                      if (n < 0)
00554                             return (-1);
00555                      if (n == 0)
00556                             goto next_ns;
00557                      if (v_circuit)
00558                        // XXX Check whether both requests failed or
00559                        // XXX whether one has been answered successfully
00560                             goto same_ns;
00561               }
00562 
00563               resplen = n;
00564 
00565               Dprint((statp->options & RES_DEBUG) ||
00566                      ((statp->pfcode & RES_PRF_REPLY) &&
00567                      (statp->pfcode & RES_PRF_HEAD1)),
00568                      (stdout, ";; got answer:\n"));
00569 
00570               DprintQ((statp->options & RES_DEBUG) ||
00571                      (statp->pfcode & RES_PRF_REPLY),
00572                      (stdout, "%s", ""),
00573                      ans, (resplen > anssiz) ? anssiz : resplen);
00574               if (buf2 != NULL)
00575                 DprintQ((statp->options & RES_DEBUG) ||
00576                        (statp->pfcode & RES_PRF_REPLY),
00577                        (stdout, "%s", ""),
00578                        *ansp2, (*resplen2 > *nansp2) ? *nansp2 : *resplen2);
00579 
00580               /*
00581                * If we have temporarily opened a virtual circuit,
00582                * or if we haven't been asked to keep a socket open,
00583                * close the socket.
00584                */
00585               if ((v_circuit && (statp->options & RES_USEVC) == 0) ||
00586                   (statp->options & RES_STAYOPEN) == 0) {
00587                      __res_iclose(statp, false);
00588               }
00589 #ifdef USE_HOOKS
00590               if (__builtin_expect (statp->rhook, 0)) {
00591                      int done = 0, loops = 0;
00592 
00593                      do {
00594                             res_sendhookact act;
00595 
00596                             act = (*statp->rhook)((struct sockaddr_in *)
00597                                                 nsap, buf, buflen,
00598                                                 ans, anssiz, &resplen);
00599                             switch (act) {
00600                             case res_goahead:
00601                             case res_done:
00602                                    done = 1;
00603                                    break;
00604                             case res_nextns:
00605                                    __res_iclose(statp, false);
00606                                    goto next_ns;
00607                             case res_modified:
00608                                    /* give the hook another try */
00609                                    if (++loops < 42) /*doug adams*/
00610                                           break;
00611                                    /*FALLTHROUGH*/
00612                             case res_error:
00613                                    /*FALLTHROUGH*/
00614                             default:
00615                                    return (-1);
00616                             }
00617                      } while (!done);
00618 
00619               }
00620 #endif
00621               return (resplen);
00622  next_ns: ;
00623           } /*foreach ns*/
00624        } /*foreach retry*/
00625        __res_iclose(statp, false);
00626        if (!v_circuit) {
00627               if (!gotsomewhere)
00628                      __set_errno (ECONNREFUSED); /* no nameservers found */
00629               else
00630                      __set_errno (ETIMEDOUT);    /* no answer obtained */
00631        } else
00632               __set_errno (terrno);
00633        return (-1);
00634 }
00635 
00636 int
00637 res_nsend(res_state statp,
00638          const u_char *buf, int buflen, u_char *ans, int anssiz)
00639 {
00640   return __libc_res_nsend(statp, buf, buflen, NULL, 0, ans, anssiz,
00641                        NULL, NULL, NULL, NULL);
00642 }
00643 libresolv_hidden_def (res_nsend)
00644 
00645 /* Private */
00646 
00647 static int
00648 send_vc(res_state statp,
00649        const u_char *buf, int buflen, const u_char *buf2, int buflen2,
00650        u_char **ansp, int *anssizp,
00651        int *terrno, int ns, u_char **anscp, u_char **ansp2, int *anssizp2,
00652        int *resplen2)
00653 {
00654        const HEADER *hp = (HEADER *) buf;
00655        const HEADER *hp2 = (HEADER *) buf2;
00656        u_char *ans = *ansp;
00657        int orig_anssizp = *anssizp;
00658        // XXX REMOVE
00659        // int anssiz = *anssizp;
00660        HEADER *anhp = (HEADER *) ans;
00661        struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
00662        int truncating, connreset, resplen, n;
00663        struct iovec iov[4];
00664        u_short len;
00665        u_short len2;
00666        u_char *cp;
00667 
00668        if (resplen2 != NULL)
00669          *resplen2 = 0;
00670        connreset = 0;
00671  same_ns:
00672        truncating = 0;
00673 
00674        /* Are we still talking to whom we want to talk to? */
00675        if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
00676               struct sockaddr_in6 peer;
00677               socklen_t size = sizeof peer;
00678 
00679               if (getpeername(statp->_vcsock,
00680                             (struct sockaddr *)&peer, &size) < 0 ||
00681                   !sock_eq(&peer, nsap)) {
00682                 __res_iclose(statp, false);
00683                      statp->_flags &= ~RES_F_VC;
00684               }
00685        }
00686 
00687        if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
00688               if (statp->_vcsock >= 0)
00689                 __res_iclose(statp, false);
00690 
00691               statp->_vcsock = socket(nsap->sin6_family, SOCK_STREAM, 0);
00692               if (statp->_vcsock < 0) {
00693                      *terrno = errno;
00694                      Perror(statp, stderr, "socket(vc)", errno);
00695                      return (-1);
00696               }
00697               __set_errno (0);
00698               if (connect(statp->_vcsock, (struct sockaddr *)nsap,
00699                          nsap->sin6_family == AF_INET
00700                          ? sizeof (struct sockaddr_in)
00701                          : sizeof (struct sockaddr_in6)) < 0) {
00702                      *terrno = errno;
00703                      Aerror(statp, stderr, "connect/vc", errno,
00704                             (struct sockaddr *) nsap);
00705                      __res_iclose(statp, false);
00706                      return (0);
00707               }
00708               statp->_flags |= RES_F_VC;
00709        }
00710 
00711        /*
00712         * Send length & message
00713         */
00714        len = htons ((u_short) buflen);
00715        evConsIovec(&len, INT16SZ, &iov[0]);
00716        evConsIovec((void*)buf, buflen, &iov[1]);
00717        int niov = 2;
00718        ssize_t explen = INT16SZ + buflen;
00719        if (buf2 != NULL) {
00720               len2 = htons ((u_short) buflen2);
00721               evConsIovec(&len2, INT16SZ, &iov[2]);
00722               evConsIovec((void*)buf2, buflen2, &iov[3]);
00723               niov = 4;
00724               explen += INT16SZ + buflen2;
00725        }
00726        if (TEMP_FAILURE_RETRY (writev(statp->_vcsock, iov, niov)) != explen) {
00727               *terrno = errno;
00728               Perror(statp, stderr, "write failed", errno);
00729               __res_iclose(statp, false);
00730               return (0);
00731        }
00732        /*
00733         * Receive length & response
00734         */
00735        int recvresp1 = 0;
00736        int recvresp2 = buf2 == NULL;
00737        uint16_t rlen16;
00738  read_len:
00739        cp = (u_char *)&rlen16;
00740        len = sizeof(rlen16);
00741        while ((n = TEMP_FAILURE_RETRY (read(statp->_vcsock, cp,
00742                                         (int)len))) > 0) {
00743               cp += n;
00744               if ((len -= n) <= 0)
00745                      break;
00746        }
00747        if (n <= 0) {
00748               *terrno = errno;
00749               Perror(statp, stderr, "read failed", errno);
00750               __res_iclose(statp, false);
00751               /*
00752                * A long running process might get its TCP
00753                * connection reset if the remote server was
00754                * restarted.  Requery the server instead of
00755                * trying a new one.  When there is only one
00756                * server, this means that a query might work
00757                * instead of failing.  We only allow one reset
00758                * per query to prevent looping.
00759                */
00760               if (*terrno == ECONNRESET && !connreset) {
00761                      connreset = 1;
00762                      goto same_ns;
00763               }
00764               return (0);
00765        }
00766        int rlen = ntohs (rlen16);
00767 
00768        int *thisanssizp;
00769        u_char **thisansp;
00770        int *thisresplenp;
00771        if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
00772               thisanssizp = anssizp;
00773               thisansp = anscp ?: ansp;
00774               assert (anscp != NULL || ansp2 == NULL);
00775               thisresplenp = &resplen;
00776        } else {
00777               if (*anssizp != MAXPACKET) {
00778                      /* No buffer allocated for the first
00779                         reply.  We can try to use the rest
00780                         of the user-provided buffer.  */
00781 #ifdef _STRING_ARCH_unaligned
00782                      *anssizp2 = orig_anssizp - resplen;
00783                      *ansp2 = *ansp + resplen;
00784 #else
00785                      int aligned_resplen
00786                        = ((resplen + __alignof__ (HEADER) - 1)
00787                           & ~(__alignof__ (HEADER) - 1));
00788                      *anssizp2 = orig_anssizp - aligned_resplen;
00789                      *ansp2 = *ansp + aligned_resplen;
00790 #endif
00791               } else {
00792                      /* The first reply did not fit into the
00793                         user-provided buffer.  Maybe the second
00794                         answer will.  */
00795                      *anssizp2 = orig_anssizp;
00796                      *ansp2 = *ansp;
00797               }
00798 
00799               thisanssizp = anssizp2;
00800               thisansp = ansp2;
00801               thisresplenp = resplen2;
00802        }
00803        anhp = (HEADER *) *thisansp;
00804 
00805        *thisresplenp = rlen;
00806        if (rlen > *thisanssizp) {
00807               /* Yes, we test ANSCP here.  If we have two buffers
00808                  both will be allocatable.  */
00809               if (__builtin_expect (anscp != NULL, 1)) {
00810                      u_char *newp = malloc (MAXPACKET);
00811                      if (newp == NULL) {
00812                             *terrno = ENOMEM;
00813                             __res_iclose(statp, false);
00814                             return (0);
00815                      }
00816                      *thisanssizp = MAXPACKET;
00817                      *thisansp = newp;
00818                      anhp = (HEADER *) newp;
00819                      len = rlen;
00820               } else {
00821                      Dprint(statp->options & RES_DEBUG,
00822                             (stdout, ";; response truncated\n")
00823                      );
00824                      truncating = 1;
00825                      len = *thisanssizp;
00826               }
00827        } else
00828               len = rlen;
00829 
00830        if (__builtin_expect (len < HFIXEDSZ, 0)) {
00831               /*
00832                * Undersized message.
00833                */
00834               Dprint(statp->options & RES_DEBUG,
00835                      (stdout, ";; undersized: %d\n", len));
00836               *terrno = EMSGSIZE;
00837               __res_iclose(statp, false);
00838               return (0);
00839        }
00840 
00841        cp = *thisansp;
00842        while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){
00843               cp += n;
00844               len -= n;
00845        }
00846        if (__builtin_expect (n <= 0, 0)) {
00847               *terrno = errno;
00848               Perror(statp, stderr, "read(vc)", errno);
00849               __res_iclose(statp, false);
00850               return (0);
00851        }
00852        if (__builtin_expect (truncating, 0)) {
00853               /*
00854                * Flush rest of answer so connection stays in synch.
00855                */
00856               anhp->tc = 1;
00857               len = rlen - *thisanssizp;
00858               while (len != 0) {
00859                      char junk[PACKETSZ];
00860 
00861                      n = read(statp->_vcsock, junk,
00862                              (len > sizeof junk) ? sizeof junk : len);
00863                      if (n > 0)
00864                             len -= n;
00865                      else
00866                             break;
00867               }
00868        }
00869        /*
00870         * If the calling applicating has bailed out of
00871         * a previous call and failed to arrange to have
00872         * the circuit closed or the server has got
00873         * itself confused, then drop the packet and
00874         * wait for the correct one.
00875         */
00876        if ((recvresp1 || hp->id != anhp->id)
00877            && (recvresp2 || hp2->id != anhp->id)) {
00878               DprintQ((statp->options & RES_DEBUG) ||
00879                      (statp->pfcode & RES_PRF_REPLY),
00880                      (stdout, ";; old answer (unexpected):\n"),
00881                      *thisansp,
00882                      (rlen > *thisanssiz) ? *thisanssiz: rlen);
00883               goto read_len;
00884        }
00885 
00886        /* Mark which reply we received.  */
00887        if (recvresp1 == 0 && hp->id == anhp->id)
00888          recvresp1 = 1;
00889        else
00890          recvresp2 = 1;
00891        /* Repeat waiting if we have a second answer to arrive.  */
00892        if ((recvresp1 & recvresp2) == 0)
00893               goto read_len;
00894 
00895        /*
00896         * All is well, or the error is fatal.  Signal that the
00897         * next nameserver ought not be tried.
00898         */
00899        return resplen;
00900 }
00901 
00902 static int
00903 send_dg(res_state statp,
00904        const u_char *buf, int buflen, const u_char *buf2, int buflen2,
00905        u_char **ansp, int *anssizp,
00906        int *terrno, int ns, int *v_circuit, int *gotsomewhere, u_char **anscp,
00907        u_char **ansp2, int *anssizp2, int *resplen2)
00908 {
00909        const HEADER *hp = (HEADER *) buf;
00910        const HEADER *hp2 = (HEADER *) buf2;
00911        u_char *ans = *ansp;
00912        int orig_anssizp = *anssizp;
00913        struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
00914        struct timespec now, timeout, finish;
00915        struct pollfd pfd[1];
00916         int ptimeout;
00917        struct sockaddr_in6 from;
00918        int resplen, seconds, n;
00919 
00920        if (EXT(statp).nssocks[ns] == -1) {
00921               /* only try IPv6 if IPv6 NS and if not failed before */
00922               if ((EXT(statp).nscount6 > 0) && !statp->ipv6_unavail) {
00923                      EXT(statp).nssocks[ns] =
00924                          socket(PF_INET6, SOCK_DGRAM, 0);
00925                      if (EXT(statp).nssocks[ns] < 0)
00926                          statp->ipv6_unavail = errno == EAFNOSUPPORT;
00927                      /* If IPv6 socket and nsap is IPv4, make it
00928                         IPv4-mapped */
00929                      else if (nsap->sin6_family == AF_INET)
00930                          convaddr4to6(nsap);
00931               }
00932               if (EXT(statp).nssocks[ns] < 0)
00933                      EXT(statp).nssocks[ns] = socket(PF_INET, SOCK_DGRAM, 0);
00934               if (EXT(statp).nssocks[ns] < 0) {
00935                      *terrno = errno;
00936                      Perror(statp, stderr, "socket(dg)", errno);
00937                      return (-1);
00938               }
00939 
00940               /*
00941                * On a 4.3BSD+ machine (client and server,
00942                * actually), sending to a nameserver datagram
00943                * port with no nameserver will cause an
00944                * ICMP port unreachable message to be returned.
00945                * If our datagram socket is "connected" to the
00946                * server, we get an ECONNREFUSED error on the next
00947                * socket operation, and select returns if the
00948                * error message is received.  We can thus detect
00949                * the absence of a nameserver without timing out.
00950                */
00951               if (connect(EXT(statp).nssocks[ns], (struct sockaddr *)nsap,
00952                          sizeof *nsap) < 0) {
00953                      Aerror(statp, stderr, "connect(dg)", errno,
00954                             (struct sockaddr *) nsap);
00955                      __res_iclose(statp, false);
00956                      return (0);
00957               }
00958               /* Make socket non-blocking.  */
00959               int fl = __fcntl (EXT(statp).nssocks[ns], F_GETFL);
00960               if  (fl != -1)
00961                      __fcntl (EXT(statp).nssocks[ns], F_SETFL,
00962                              fl | O_NONBLOCK);
00963               Dprint(statp->options & RES_DEBUG,
00964                      (stdout, ";; new DG socket\n"))
00965        }
00966 
00967        /*
00968         * Compute time for the total operation.
00969         */
00970        seconds = (statp->retrans << ns);
00971        if (ns > 0)
00972               seconds /= statp->nscount;
00973        if (seconds <= 0)
00974               seconds = 1;
00975        evNowTime(&now);
00976        evConsTime(&timeout, seconds, 0);
00977        evAddTime(&finish, &now, &timeout);
00978        int need_recompute = 0;
00979        int nwritten = 0;
00980        int recvresp1 = 0;
00981        int recvresp2 = buf2 == NULL;
00982        pfd[0].fd = EXT(statp).nssocks[ns];
00983        pfd[0].events = POLLOUT;
00984        if (resplen2 != NULL)
00985          *resplen2 = 0;
00986  wait:
00987        if (need_recompute) {
00988        recompute_resend:
00989               evNowTime(&now);
00990               if (evCmpTime(finish, now) <= 0) {
00991               poll_err_out:
00992                      Perror(statp, stderr, "poll", errno);
00993               err_out:
00994                      __res_iclose(statp, false);
00995                      return (0);
00996               }
00997               evSubTime(&timeout, &finish, &now);
00998        }
00999         /* Convert struct timespec in milliseconds.  */
01000        ptimeout = timeout.tv_sec * 1000 + timeout.tv_nsec / 1000000;
01001 
01002        n = 0;
01003        if (nwritten == 0)
01004          n = __poll (pfd, 1, 0);
01005        if (__builtin_expect (n == 0, 0)) {
01006               n = __poll (pfd, 1, ptimeout);
01007               need_recompute = 1;
01008        }
01009        if (n == 0) {
01010               Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
01011               if (resplen > 1 && (recvresp1 || (buf2 != NULL && recvresp2)))
01012                 {
01013                   *resplen2 = 1;
01014                   return resplen;
01015                 }
01016 
01017               *gotsomewhere = 1;
01018               return (0);
01019        }
01020        if (n < 0) {
01021               if (errno == EINTR)
01022                      goto recompute_resend;
01023 
01024               goto poll_err_out;
01025        }
01026        __set_errno (0);
01027        if (pfd[0].revents & POLLOUT) {
01028               ssize_t sr;
01029               if (nwritten != 0)
01030                 sr = send (pfd[0].fd, buf2, buflen2, MSG_NOSIGNAL);
01031               else
01032                 sr = send (pfd[0].fd, buf, buflen, MSG_NOSIGNAL);
01033 
01034               if (sr != buflen) {
01035                      if (errno == EINTR || errno == EAGAIN)
01036                             goto recompute_resend;
01037                      Perror(statp, stderr, "send", errno);
01038                      goto err_out;
01039               }
01040               if (nwritten != 0 || buf2 == NULL)
01041                 pfd[0].events = POLLIN;
01042               else
01043                 pfd[0].events = POLLIN | POLLOUT;
01044               ++nwritten;
01045               goto wait;
01046        } else if (pfd[0].revents & POLLIN) {
01047               int *thisanssizp;
01048               u_char **thisansp;
01049               int *thisresplenp;
01050 
01051               if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
01052                      thisanssizp = anssizp;
01053                      thisansp = anscp ?: ansp;
01054                      assert (anscp != NULL || ansp2 == NULL);
01055                      thisresplenp = &resplen;
01056               } else {
01057                      if (*anssizp != MAXPACKET) {
01058                             /* No buffer allocated for the first
01059                                reply.  We can try to use the rest
01060                                of the user-provided buffer.  */
01061 #ifdef _STRING_ARCH_unaligned
01062                             *anssizp2 = orig_anssizp - resplen;
01063                             *ansp2 = *ansp + resplen;
01064 #else
01065                             int aligned_resplen
01066                               = ((resplen + __alignof__ (HEADER) - 1)
01067                                  & ~(__alignof__ (HEADER) - 1));
01068                             *anssizp2 = orig_anssizp - aligned_resplen;
01069                             *ansp2 = *ansp + aligned_resplen;
01070 #endif
01071                      } else {
01072                             /* The first reply did not fit into the
01073                                user-provided buffer.  Maybe the second
01074                                answer will.  */
01075                             *anssizp2 = orig_anssizp;
01076                             *ansp2 = *ansp;
01077                      }
01078 
01079                      thisanssizp = anssizp2;
01080                      thisansp = ansp2;
01081                      thisresplenp = resplen2;
01082               }
01083 
01084               if (*thisanssizp < MAXPACKET
01085                   /* Yes, we test ANSCP here.  If we have two buffers
01086                      both will be allocatable.  */
01087                   && anscp
01088                   && (ioctl (pfd[0].fd, FIONREAD, thisresplenp) < 0
01089                      || *thisanssizp < *thisresplenp)) {
01090                      u_char *newp = malloc (MAXPACKET);
01091                      if (newp != NULL) {
01092                             *anssizp = MAXPACKET;
01093                             *thisansp = ans = newp;
01094                      }
01095               }
01096               HEADER *anhp = (HEADER *) *thisansp;
01097               socklen_t fromlen = sizeof(struct sockaddr_in6);
01098               assert (sizeof(from) <= fromlen);
01099               *thisresplenp = recvfrom(pfd[0].fd, (char*)*thisansp,
01100                                     *thisanssizp, 0,
01101                                    (struct sockaddr *)&from, &fromlen);
01102               if (__builtin_expect (*thisresplenp <= 0, 0)) {
01103                      if (errno == EINTR || errno == EAGAIN) {
01104                             need_recompute = 1;
01105                             goto wait;
01106                      }
01107                      Perror(statp, stderr, "recvfrom", errno);
01108                      goto err_out;
01109               }
01110               *gotsomewhere = 1;
01111               if (__builtin_expect (*thisresplenp < HFIXEDSZ, 0)) {
01112                      /*
01113                       * Undersized message.
01114                       */
01115                      Dprint(statp->options & RES_DEBUG,
01116                             (stdout, ";; undersized: %d\n",
01117                             *thisresplen));
01118                      *terrno = EMSGSIZE;
01119                      goto err_out;
01120               }
01121               if ((recvresp1 || hp->id != anhp->id)
01122                   && (recvresp2 || hp2->id != anhp->id)) {
01123                      /*
01124                       * response from old query, ignore it.
01125                       * XXX - potential security hazard could
01126                       *      be detected here.
01127                       */
01128                      DprintQ((statp->options & RES_DEBUG) ||
01129                             (statp->pfcode & RES_PRF_REPLY),
01130                             (stdout, ";; old answer:\n"),
01131                             thisansp,
01132                             (*thisresplen > *thisanssiz)
01133                             ? *thisanssiz : *thisresplen);
01134                      goto wait;
01135               }
01136               if (!(statp->options & RES_INSECURE1) &&
01137                   !res_ourserver_p(statp, &from)) {
01138                      /*
01139                       * response from wrong server? ignore it.
01140                       * XXX - potential security hazard could
01141                       *      be detected here.
01142                       */
01143                      DprintQ((statp->options & RES_DEBUG) ||
01144                             (statp->pfcode & RES_PRF_REPLY),
01145                             (stdout, ";; not our server:\n"),
01146                             thisansp,
01147                             (*thisresplen > *thisanssiz)
01148                             ? *thisanssiz : *thisresplen);
01149                      goto wait;
01150               }
01151 #ifdef RES_USE_EDNS0
01152               if (anhp->rcode == FORMERR
01153                   && (statp->options & RES_USE_EDNS0) != 0U) {
01154                      /*
01155                       * Do not retry if the server does not understand
01156                       * EDNS0.  The case has to be captured here, as
01157                       * FORMERR packet do not carry query section, hence
01158                       * res_queriesmatch() returns 0.
01159                       */
01160                      DprintQ(statp->options & RES_DEBUG,
01161                             (stdout,
01162                              "server rejected query with EDNS0:\n"),
01163                             thisans,
01164                             (*thisresplen > *thisanssiz)
01165                             ? *thisanssiz : *thisresplen);
01166                      /* record the error */
01167                      statp->_flags |= RES_F_EDNS0ERR;
01168                      goto err_out;
01169         }
01170 #endif
01171               if (!(statp->options & RES_INSECURE2)
01172                   && (recvresp1 || !res_queriesmatch(buf, buf + buflen,
01173                                                  *thisansp,
01174                                                  *thisansp
01175                                                  + *thisanssizp))
01176                   && (recvresp2 || !res_queriesmatch(buf2, buf2 + buflen2,
01177                                                  *thisansp,
01178                                                  *thisansp
01179                                                  + *thisanssizp))) {
01180                      /*
01181                       * response contains wrong query? ignore it.
01182                       * XXX - potential security hazard could
01183                       *      be detected here.
01184                       */
01185                      DprintQ((statp->options & RES_DEBUG) ||
01186                             (statp->pfcode & RES_PRF_REPLY),
01187                             (stdout, ";; wrong query name:\n"),
01188                             thisansp,
01189                             (*thisresplen > *thisanssiz)
01190                             ? *thisanssiz : *thisresplen);
01191                      goto wait;
01192               }
01193               if (anhp->rcode == SERVFAIL ||
01194                   anhp->rcode == NOTIMP ||
01195                   anhp->rcode == REFUSED) {
01196                      DprintQ(statp->options & RES_DEBUG,
01197                             (stdout, "server rejected query:\n"),
01198                             thisansp,
01199                             (*thisresplen > *thisanssiz)
01200                             ? *thisanssiz : *thisresplen);
01201 
01202                      if (recvresp1 || (buf2 != NULL && recvresp2))
01203                        {
01204                          *resplen2 = 1;
01205                          return resplen;
01206                        }
01207                      if (buf2 != NULL)
01208                        {
01209                          /* We are waiting for a possible second reply.  */
01210                          resplen = 1;
01211                          if (hp->id == anhp->id)
01212                            recvresp1 = 1;
01213                          else
01214                            recvresp2 = 1;
01215 
01216                          goto wait;
01217                        }
01218 
01219               next_ns:
01220                      __res_iclose(statp, false);
01221                      /* don't retry if called from dig */
01222                      if (!statp->pfcode)
01223                             return (0);
01224               }
01225               if (anhp->rcode == NOERROR && anhp->ancount == 0
01226                   && anhp->aa == 0 && anhp->ra == 0 && anhp->arcount == 0) {
01227                      DprintQ(statp->options & RES_DEBUG,
01228                             (stdout, "referred query:\n"),
01229                             thisansp,
01230                             (*thisresplen > *thisanssiz)
01231                             ? *thisanssiz : *thisresplen);
01232                      goto next_ns;
01233               }
01234               if (!(statp->options & RES_IGNTC) && anhp->tc) {
01235                      /*
01236                       * To get the rest of answer,
01237                       * use TCP with same server.
01238                       */
01239                      Dprint(statp->options & RES_DEBUG,
01240                             (stdout, ";; truncated answer\n"));
01241                      *v_circuit = 1;
01242                      __res_iclose(statp, false);
01243                      // XXX if we have received one reply we could
01244                      // XXX use it and not repeat it over TCP...
01245                      return (1);
01246               }
01247               /* Mark which reply we received.  */
01248               if (recvresp1 == 0 && hp->id == anhp->id)
01249                      recvresp1 = 1;
01250               else
01251                      recvresp2 = 1;
01252               /* Repeat waiting if we have a second answer to arrive.  */
01253               if ((recvresp1 & recvresp2) == 0)
01254                      goto wait;
01255               /*
01256                * All is well, or the error is fatal.  Signal that the
01257                * next nameserver ought not be tried.
01258                */
01259               return (resplen);
01260        } else if (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
01261               /* Something went wrong.  We can stop trying.  */
01262               goto err_out;
01263        }
01264        else {
01265               /* poll should not have returned > 0 in this case.  */
01266               abort ();
01267        }
01268 }
01269 
01270 #ifdef DEBUG
01271 static void
01272 Aerror(const res_state statp, FILE *file, const char *string, int error,
01273        const struct sockaddr *address)
01274 {
01275        int save = errno;
01276 
01277        if ((statp->options & RES_DEBUG) != 0) {
01278               char tmp[sizeof "xxxx.xxxx.xxxx.255.255.255.255"];
01279 
01280               fprintf(file, "res_send: %s ([%s].%u): %s\n",
01281                      string,
01282                      (address->sa_family == AF_INET
01283                       ? inet_ntop(address->sa_family,
01284                                  &((const struct sockaddr_in *) address)->sin_addr,
01285                                  tmp, sizeof tmp)
01286                       : inet_ntop(address->sa_family,
01287                                  &((const struct sockaddr_in6 *) address)->sin6_addr,
01288                                  tmp, sizeof tmp)),
01289                      (address->sa_family == AF_INET
01290                       ? ntohs(((struct sockaddr_in *) address)->sin_port)
01291                       : address->sa_family == AF_INET6
01292                       ? ntohs(((struct sockaddr_in6 *) address)->sin6_port)
01293                       : 0),
01294                      strerror(error));
01295        }
01296        __set_errno (save);
01297 }
01298 
01299 static void
01300 Perror(const res_state statp, FILE *file, const char *string, int error) {
01301        int save = errno;
01302 
01303        if ((statp->options & RES_DEBUG) != 0)
01304               fprintf(file, "res_send: %s: %s\n",
01305                      string, strerror(error));
01306        __set_errno (save);
01307 }
01308 #endif
01309 
01310 static int
01311 sock_eq(struct sockaddr_in6 *a1, struct sockaddr_in6 *a2) {
01312        if (a1->sin6_family == a2->sin6_family) {
01313               if (a1->sin6_family == AF_INET)
01314                      return ((((struct sockaddr_in *)a1)->sin_port ==
01315                              ((struct sockaddr_in *)a2)->sin_port) &&
01316                             (((struct sockaddr_in *)a1)->sin_addr.s_addr ==
01317                              ((struct sockaddr_in *)a2)->sin_addr.s_addr));
01318               else
01319                      return ((a1->sin6_port == a2->sin6_port) &&
01320                             !memcmp(&a1->sin6_addr, &a2->sin6_addr,
01321                                    sizeof (struct in6_addr)));
01322        }
01323        if (a1->sin6_family == AF_INET) {
01324               struct sockaddr_in6 *sap = a1;
01325               a1 = a2;
01326               a2 = sap;
01327        } /* assumes that AF_INET and AF_INET6 are the only possibilities */
01328        return ((a1->sin6_port == ((struct sockaddr_in *)a2)->sin_port) &&
01329               IN6_IS_ADDR_V4MAPPED(&a1->sin6_addr) &&
01330               (a1->sin6_addr.s6_addr32[3] ==
01331                ((struct sockaddr_in *)a2)->sin_addr.s_addr));
01332 }
01333 
01334 /*
01335  * Converts IPv4 family, address and port to
01336  * IPv6 family, IPv4-mapped IPv6 address and port.
01337  */
01338 static void
01339 convaddr4to6(struct sockaddr_in6 *sa)
01340 {
01341     struct sockaddr_in *sa4p = (struct sockaddr_in *) sa;
01342     in_port_t port = sa4p->sin_port;
01343     in_addr_t addr = sa4p->sin_addr.s_addr;
01344 
01345     sa->sin6_family = AF_INET6;
01346     sa->sin6_port = port;
01347     sa->sin6_addr.s6_addr32[0] = 0;
01348     sa->sin6_addr.s6_addr32[1] = 0;
01349     sa->sin6_addr.s6_addr32[2] = htonl(0xFFFF);
01350     sa->sin6_addr.s6_addr32[3] = addr;
01351 }