123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440 |
- /* Copyright (C) 2016-2019 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
- /*
- * Copyright (c) 1985, 1989, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
- /*
- * Portions Copyright (c) 1993 by Digital Equipment Corporation.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies, and that
- * the name of Digital Equipment Corporation not be used in advertising or
- * publicity pertaining to distribution of the document or software without
- * specific, written prior permission.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
- * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- */
- /*
- * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
- * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
- * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- */
- /*
- * Send query to name server and wait for reply.
- */
- #include <assert.h>
- #include <sys/types.h>
- #include <sys/param.h>
- #include <sys/time.h>
- #include <sys/socket.h>
- #include <sys/uio.h>
- #include <sys/poll.h>
- #include <netinet/in.h>
- #include <arpa/nameser.h>
- #include <arpa/inet.h>
- #include <sys/ioctl.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <netdb.h>
- #include <resolv/resolv-internal.h>
- #include <resolv/resolv_context.h>
- #include <signal.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <kernel-features.h>
- #include <libc-diag.h>
- #include <hp-timing.h>
- #if PACKETSZ > 65536
- #define MAXPACKET PACKETSZ
- #else
- #define MAXPACKET 65536
- #endif
- /* From ev_streams.c. */
- static inline void
- __attribute ((always_inline))
- evConsIovec(void *buf, size_t cnt, struct iovec *vec) {
- memset(vec, 0xf5, sizeof (*vec));
- vec->iov_base = buf;
- vec->iov_len = cnt;
- }
- /* From ev_timers.c. */
- #define BILLION 1000000000
- static inline void
- evConsTime(struct timespec *res, time_t sec, long nsec) {
- res->tv_sec = sec;
- res->tv_nsec = nsec;
- }
- static inline void
- evAddTime(struct timespec *res, const struct timespec *addend1,
- const struct timespec *addend2) {
- res->tv_sec = addend1->tv_sec + addend2->tv_sec;
- res->tv_nsec = addend1->tv_nsec + addend2->tv_nsec;
- if (res->tv_nsec >= BILLION) {
- res->tv_sec++;
- res->tv_nsec -= BILLION;
- }
- }
- static inline void
- evSubTime(struct timespec *res, const struct timespec *minuend,
- const struct timespec *subtrahend) {
- res->tv_sec = minuend->tv_sec - subtrahend->tv_sec;
- if (minuend->tv_nsec >= subtrahend->tv_nsec)
- res->tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec;
- else {
- res->tv_nsec = (BILLION
- - subtrahend->tv_nsec + minuend->tv_nsec);
- res->tv_sec--;
- }
- }
- static int
- evCmpTime(struct timespec a, struct timespec b) {
- long x = a.tv_sec - b.tv_sec;
- if (x == 0L)
- x = a.tv_nsec - b.tv_nsec;
- return (x < 0L ? (-1) : x > 0L ? (1) : (0));
- }
- static void
- evNowTime(struct timespec *res) {
- struct timeval now;
- if (gettimeofday(&now, NULL) < 0)
- evConsTime(res, 0, 0);
- else
- TIMEVAL_TO_TIMESPEC (&now, res);
- }
- #define EXT(res) ((res)->_u._ext)
- /* Forward. */
- static struct sockaddr *get_nsaddr (res_state, unsigned int);
- static int send_vc(res_state, const u_char *, int,
- const u_char *, int,
- u_char **, int *, int *, int, u_char **,
- u_char **, int *, int *, int *);
- static int send_dg(res_state, const u_char *, int,
- const u_char *, int,
- u_char **, int *, int *, int,
- int *, int *, u_char **,
- u_char **, int *, int *, int *);
- static int sock_eq(struct sockaddr_in6 *, struct sockaddr_in6 *);
- /* Public. */
- /* int
- * res_isourserver(ina)
- * looks up "ina" in _res.ns_addr_list[]
- * returns:
- * 0 : not found
- * >0 : found
- * author:
- * paul vixie, 29may94
- */
- int
- res_ourserver_p(const res_state statp, const struct sockaddr_in6 *inp)
- {
- int ns;
- if (inp->sin6_family == AF_INET) {
- struct sockaddr_in *in4p = (struct sockaddr_in *) inp;
- in_port_t port = in4p->sin_port;
- in_addr_t addr = in4p->sin_addr.s_addr;
- for (ns = 0; ns < statp->nscount; ns++) {
- const struct sockaddr_in *srv =
- (struct sockaddr_in *) get_nsaddr (statp, ns);
- if ((srv->sin_family == AF_INET) &&
- (srv->sin_port == port) &&
- (srv->sin_addr.s_addr == INADDR_ANY ||
- srv->sin_addr.s_addr == addr))
- return (1);
- }
- } else if (inp->sin6_family == AF_INET6) {
- for (ns = 0; ns < statp->nscount; ns++) {
- const struct sockaddr_in6 *srv
- = (struct sockaddr_in6 *) get_nsaddr (statp, ns);
- if ((srv->sin6_family == AF_INET6) &&
- (srv->sin6_port == inp->sin6_port) &&
- !(memcmp(&srv->sin6_addr, &in6addr_any,
- sizeof (struct in6_addr)) &&
- memcmp(&srv->sin6_addr, &inp->sin6_addr,
- sizeof (struct in6_addr))))
- return (1);
- }
- }
- return (0);
- }
- int
- res_isourserver (const struct sockaddr_in *inp)
- {
- return res_ourserver_p (&_res, (const struct sockaddr_in6 *) inp);
- }
- /* int
- * res_nameinquery(name, type, class, buf, eom)
- * look for (name,type,class) in the query section of packet (buf,eom)
- * requires:
- * buf + HFIXEDSZ <= eom
- * returns:
- * -1 : format error
- * 0 : not found
- * >0 : found
- * author:
- * paul vixie, 29may94
- */
- int
- res_nameinquery(const char *name, int type, int class,
- const u_char *buf, const u_char *eom)
- {
- const u_char *cp = buf + HFIXEDSZ;
- int qdcount = ntohs(((HEADER*)buf)->qdcount);
- while (qdcount-- > 0) {
- char tname[MAXDNAME+1];
- int n, ttype, tclass;
- n = dn_expand(buf, eom, cp, tname, sizeof tname);
- if (n < 0)
- return (-1);
- cp += n;
- if (cp + 2 * INT16SZ > eom)
- return (-1);
- NS_GET16(ttype, cp);
- NS_GET16(tclass, cp);
- if (ttype == type && tclass == class &&
- ns_samename(tname, name) == 1)
- return (1);
- }
- return (0);
- }
- libresolv_hidden_def (res_nameinquery)
- /* Returns a shift value for the name server index. Used to implement
- RES_ROTATE. */
- static unsigned int
- nameserver_offset (struct __res_state *statp)
- {
- /* If we only have one name server or rotation is disabled, return
- offset 0 (no rotation). */
- unsigned int nscount = statp->nscount;
- if (nscount <= 1 || !(statp->options & RES_ROTATE))
- return 0;
- /* Global offset. The lowest bit indicates whether the offset has
- been initialized with a random value. Use relaxed MO to access
- global_offset because all we need is a sequence of roughly
- sequential value. */
- static unsigned int global_offset;
- unsigned int offset = atomic_fetch_add_relaxed (&global_offset, 2);
- if ((offset & 1) == 0)
- {
- /* Initialization is required. */
- #if HP_TIMING_AVAIL
- uint64_t ticks;
- HP_TIMING_NOW (ticks);
- offset = ticks;
- #else
- struct timeval tv;
- __gettimeofday (&tv, NULL);
- offset = ((tv.tv_sec << 8) ^ tv.tv_usec);
- #endif
- /* The lowest bit is the most random. Preserve it. */
- offset <<= 1;
- /* Store the new starting value. atomic_fetch_add_relaxed
- returns the old value, so emulate that by storing the new
- (incremented) value. Concurrent initialization with
- different random values is harmless. */
- atomic_store_relaxed (&global_offset, (offset | 1) + 2);
- }
- /* Remove the initialization bit. */
- offset >>= 1;
- /* Avoid the division in the most common cases. */
- switch (nscount)
- {
- case 2:
- return offset & 1;
- case 3:
- return offset % 3;
- case 4:
- return offset & 3;
- default:
- return offset % nscount;
- }
- }
- /* int
- * res_queriesmatch(buf1, eom1, buf2, eom2)
- * is there a 1:1 mapping of (name,type,class)
- * in (buf1,eom1) and (buf2,eom2)?
- * returns:
- * -1 : format error
- * 0 : not a 1:1 mapping
- * >0 : is a 1:1 mapping
- * author:
- * paul vixie, 29may94
- */
- int
- res_queriesmatch(const u_char *buf1, const u_char *eom1,
- const u_char *buf2, const u_char *eom2)
- {
- if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
- return (-1);
- /*
- * Only header section present in replies to
- * dynamic update packets.
- */
- if ((((HEADER *)buf1)->opcode == ns_o_update) &&
- (((HEADER *)buf2)->opcode == ns_o_update))
- return (1);
- /* Note that we initially do not convert QDCOUNT to the host byte
- order. We can compare it with the second buffer's QDCOUNT
- value without doing this. */
- int qdcount = ((HEADER*)buf1)->qdcount;
- if (qdcount != ((HEADER*)buf2)->qdcount)
- return (0);
- qdcount = htons (qdcount);
- const u_char *cp = buf1 + HFIXEDSZ;
- while (qdcount-- > 0) {
- char tname[MAXDNAME+1];
- int n, ttype, tclass;
- n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
- if (n < 0)
- return (-1);
- cp += n;
- if (cp + 2 * INT16SZ > eom1)
- return (-1);
- NS_GET16(ttype, cp);
- NS_GET16(tclass, cp);
- if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
- return (0);
- }
- return (1);
- }
- libresolv_hidden_def (res_queriesmatch)
- int
- __res_context_send (struct resolv_context *ctx,
- const unsigned char *buf, int buflen,
- const unsigned char *buf2, int buflen2,
- unsigned char *ans, int anssiz,
- unsigned char **ansp, unsigned char **ansp2,
- int *nansp2, int *resplen2, int *ansp2_malloced)
- {
- struct __res_state *statp = ctx->resp;
- int gotsomewhere, terrno, try, v_circuit, resplen, n;
- if (statp->nscount == 0) {
- __set_errno (ESRCH);
- return (-1);
- }
- if (anssiz < (buf2 == NULL ? 1 : 2) * HFIXEDSZ) {
- __set_errno (EINVAL);
- return (-1);
- }
- v_circuit = ((statp->options & RES_USEVC)
- || buflen > PACKETSZ
- || buflen2 > PACKETSZ);
- gotsomewhere = 0;
- terrno = ETIMEDOUT;
- /*
- * If the ns_addr_list in the resolver context has changed, then
- * invalidate our cached copy and the associated timing data.
- */
- if (EXT(statp).nscount != 0) {
- int needclose = 0;
- if (EXT(statp).nscount != statp->nscount)
- needclose++;
- else
- for (unsigned int ns = 0; ns < statp->nscount; ns++) {
- if (statp->nsaddr_list[ns].sin_family != 0
- && !sock_eq((struct sockaddr_in6 *)
- &statp->nsaddr_list[ns],
- EXT(statp).nsaddrs[ns]))
- {
- needclose++;
- break;
- }
- }
- if (needclose) {
- __res_iclose(statp, false);
- EXT(statp).nscount = 0;
- }
- }
- /*
- * Maybe initialize our private copy of the ns_addr_list.
- */
- if (EXT(statp).nscount == 0) {
- for (unsigned int ns = 0; ns < statp->nscount; ns++) {
- EXT(statp).nssocks[ns] = -1;
- if (statp->nsaddr_list[ns].sin_family == 0)
- continue;
- if (EXT(statp).nsaddrs[ns] == NULL)
- EXT(statp).nsaddrs[ns] =
- malloc(sizeof (struct sockaddr_in6));
- if (EXT(statp).nsaddrs[ns] != NULL)
- memset (mempcpy(EXT(statp).nsaddrs[ns],
- &statp->nsaddr_list[ns],
- sizeof (struct sockaddr_in)),
- '\0',
- sizeof (struct sockaddr_in6)
- - sizeof (struct sockaddr_in));
- else
- return -1;
- }
- EXT(statp).nscount = statp->nscount;
- }
- /* Name server index offset. Used to implement
- RES_ROTATE. */
- unsigned int ns_offset = nameserver_offset (statp);
- /*
- * Send request, RETRY times, or until successful.
- */
- for (try = 0; try < statp->retry; try++) {
- for (unsigned ns_shift = 0; ns_shift < statp->nscount; ns_shift++)
- {
- /* The actual name server index. This implements
- RES_ROTATE. */
- unsigned int ns = ns_shift + ns_offset;
- if (ns >= statp->nscount)
- ns -= statp->nscount;
- same_ns:
- if (__glibc_unlikely (v_circuit)) {
- /* Use VC; at most one attempt per server. */
- try = statp->retry;
- n = send_vc(statp, buf, buflen, buf2, buflen2,
- &ans, &anssiz, &terrno,
- ns, ansp, ansp2, nansp2, resplen2,
- ansp2_malloced);
- if (n < 0)
- return (-1);
- if (n == 0 && (buf2 == NULL || *resplen2 == 0))
- goto next_ns;
- } else {
- /* Use datagrams. */
- n = send_dg(statp, buf, buflen, buf2, buflen2,
- &ans, &anssiz, &terrno,
- ns, &v_circuit, &gotsomewhere, ansp,
- ansp2, nansp2, resplen2, ansp2_malloced);
- if (n < 0)
- return (-1);
- if (n == 0 && (buf2 == NULL || *resplen2 == 0))
- goto next_ns;
- if (v_circuit)
- // XXX Check whether both requests failed or
- // XXX whether one has been answered successfully
- goto same_ns;
- }
- resplen = n;
- /*
- * If we have temporarily opened a virtual circuit,
- * or if we haven't been asked to keep a socket open,
- * close the socket.
- */
- if ((v_circuit && (statp->options & RES_USEVC) == 0) ||
- (statp->options & RES_STAYOPEN) == 0) {
- __res_iclose(statp, false);
- }
- return (resplen);
- next_ns: ;
- } /*foreach ns*/
- } /*foreach retry*/
- __res_iclose(statp, false);
- if (!v_circuit) {
- if (!gotsomewhere)
- __set_errno (ECONNREFUSED); /* no nameservers found */
- else
- __set_errno (ETIMEDOUT); /* no answer obtained */
- } else
- __set_errno (terrno);
- return (-1);
- }
- /* Common part of res_nsend and res_send. */
- static int
- context_send_common (struct resolv_context *ctx,
- const unsigned char *buf, int buflen,
- unsigned char *ans, int anssiz)
- {
- if (ctx == NULL)
- {
- RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
- return -1;
- }
- int result = __res_context_send (ctx, buf, buflen, NULL, 0, ans, anssiz,
- NULL, NULL, NULL, NULL, NULL);
- __resolv_context_put (ctx);
- return result;
- }
- int
- res_nsend (res_state statp, const unsigned char *buf, int buflen,
- unsigned char *ans, int anssiz)
- {
- return context_send_common
- (__resolv_context_get_override (statp), buf, buflen, ans, anssiz);
- }
- int
- res_send (const unsigned char *buf, int buflen, unsigned char *ans, int anssiz)
- {
- return context_send_common
- (__resolv_context_get (), buf, buflen, ans, anssiz);
- }
- /* Private */
- static struct sockaddr *
- get_nsaddr (res_state statp, unsigned int n)
- {
- assert (n < statp->nscount);
- if (statp->nsaddr_list[n].sin_family == 0 && EXT(statp).nsaddrs[n] != NULL)
- /* EXT(statp).nsaddrs[n] holds an address that is larger than
- struct sockaddr, and user code did not update
- statp->nsaddr_list[n]. */
- return (struct sockaddr *) EXT(statp).nsaddrs[n];
- else
- /* User code updated statp->nsaddr_list[n], or statp->nsaddr_list[n]
- has the same content as EXT(statp).nsaddrs[n]. */
- return (struct sockaddr *) (void *) &statp->nsaddr_list[n];
- }
- /* Close the resolver structure, assign zero to *RESPLEN2 if RESPLEN2
- is not NULL, and return zero. */
- static int
- __attribute__ ((warn_unused_result))
- close_and_return_error (res_state statp, int *resplen2)
- {
- __res_iclose(statp, false);
- if (resplen2 != NULL)
- *resplen2 = 0;
- return 0;
- }
- /* The send_vc function is responsible for sending a DNS query over TCP
- to the nameserver numbered NS from the res_state STATP i.e.
- EXT(statp).nssocks[ns]. The function supports sending both IPv4 and
- IPv6 queries at the same serially on the same socket.
- Please note that for TCP there is no way to disable sending both
- queries, unlike UDP, which honours RES_SNGLKUP and RES_SNGLKUPREOP
- and sends the queries serially and waits for the result after each
- sent query. This implementation should be corrected to honour these
- options.
- Please also note that for TCP we send both queries over the same
- socket one after another. This technically violates best practice
- since the server is allowed to read the first query, respond, and
- then close the socket (to service another client). If the server
- does this, then the remaining second query in the socket data buffer
- will cause the server to send the client an RST which will arrive
- asynchronously and the client's OS will likely tear down the socket
- receive buffer resulting in a potentially short read and lost
- response data. This will force the client to retry the query again,
- and this process may repeat until all servers and connection resets
- are exhausted and then the query will fail. It's not known if this
- happens with any frequency in real DNS server implementations. This
- implementation should be corrected to use two sockets by default for
- parallel queries.
- The query stored in BUF of BUFLEN length is sent first followed by
- the query stored in BUF2 of BUFLEN2 length. Queries are sent
- serially on the same socket.
- Answers to the query are stored firstly in *ANSP up to a max of
- *ANSSIZP bytes. If more than *ANSSIZP bytes are needed and ANSCP
- is non-NULL (to indicate that modifying the answer buffer is allowed)
- then malloc is used to allocate a new response buffer and ANSCP and
- ANSP will both point to the new buffer. If more than *ANSSIZP bytes
- are needed but ANSCP is NULL, then as much of the response as
- possible is read into the buffer, but the results will be truncated.
- When truncation happens because of a small answer buffer the DNS
- packets header field TC will bet set to 1, indicating a truncated
- message and the rest of the socket data will be read and discarded.
- Answers to the query are stored secondly in *ANSP2 up to a max of
- *ANSSIZP2 bytes, with the actual response length stored in
- *RESPLEN2. If more than *ANSSIZP bytes are needed and ANSP2
- is non-NULL (required for a second query) then malloc is used to
- allocate a new response buffer, *ANSSIZP2 is set to the new buffer
- size and *ANSP2_MALLOCED is set to 1.
- The ANSP2_MALLOCED argument will eventually be removed as the
- change in buffer pointer can be used to detect the buffer has
- changed and that the caller should use free on the new buffer.
- Note that the answers may arrive in any order from the server and
- therefore the first and second answer buffers may not correspond to
- the first and second queries.
- It is not supported to call this function with a non-NULL ANSP2
- but a NULL ANSCP. Put another way, you can call send_vc with a
- single unmodifiable buffer or two modifiable buffers, but no other
- combination is supported.
- It is the caller's responsibility to free the malloc allocated
- buffers by detecting that the pointers have changed from their
- original values i.e. *ANSCP or *ANSP2 has changed.
- If errors are encountered then *TERRNO is set to an appropriate
- errno value and a zero result is returned for a recoverable error,
- and a less-than zero result is returned for a non-recoverable error.
- If no errors are encountered then *TERRNO is left unmodified and
- a the length of the first response in bytes is returned. */
- static int
- send_vc(res_state statp,
- const u_char *buf, int buflen, const u_char *buf2, int buflen2,
- u_char **ansp, int *anssizp,
- int *terrno, int ns, u_char **anscp, u_char **ansp2, int *anssizp2,
- int *resplen2, int *ansp2_malloced)
- {
- const HEADER *hp = (HEADER *) buf;
- const HEADER *hp2 = (HEADER *) buf2;
- HEADER *anhp = (HEADER *) *ansp;
- struct sockaddr *nsap = get_nsaddr (statp, ns);
- int truncating, connreset, n;
- /* On some architectures compiler might emit a warning indicating
- 'resplen' may be used uninitialized. However if buf2 == NULL
- then this code won't be executed; if buf2 != NULL, then first
- time round the loop recvresp1 and recvresp2 will be 0 so this
- code won't be executed but "thisresplenp = &resplen;" followed
- by "*thisresplenp = rlen;" will be executed so that subsequent
- times round the loop resplen has been initialized. So this is
- a false-positive.
- */
- DIAG_PUSH_NEEDS_COMMENT;
- DIAG_IGNORE_NEEDS_COMMENT (5, "-Wmaybe-uninitialized");
- int resplen;
- DIAG_POP_NEEDS_COMMENT;
- struct iovec iov[4];
- u_short len;
- u_short len2;
- u_char *cp;
- connreset = 0;
- same_ns:
- truncating = 0;
- /* Are we still talking to whom we want to talk to? */
- if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
- struct sockaddr_in6 peer;
- socklen_t size = sizeof peer;
- if (getpeername(statp->_vcsock,
- (struct sockaddr *)&peer, &size) < 0 ||
- !sock_eq(&peer, (struct sockaddr_in6 *) nsap)) {
- __res_iclose(statp, false);
- statp->_flags &= ~RES_F_VC;
- }
- }
- if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
- if (statp->_vcsock >= 0)
- __res_iclose(statp, false);
- statp->_vcsock = socket
- (nsap->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0);
- if (statp->_vcsock < 0) {
- *terrno = errno;
- if (resplen2 != NULL)
- *resplen2 = 0;
- return (-1);
- }
- __set_errno (0);
- if (connect(statp->_vcsock, nsap,
- nsap->sa_family == AF_INET
- ? sizeof (struct sockaddr_in)
- : sizeof (struct sockaddr_in6)) < 0) {
- *terrno = errno;
- return close_and_return_error (statp, resplen2);
- }
- statp->_flags |= RES_F_VC;
- }
- /*
- * Send length & message
- */
- len = htons ((u_short) buflen);
- evConsIovec(&len, INT16SZ, &iov[0]);
- evConsIovec((void*)buf, buflen, &iov[1]);
- int niov = 2;
- ssize_t explen = INT16SZ + buflen;
- if (buf2 != NULL) {
- len2 = htons ((u_short) buflen2);
- evConsIovec(&len2, INT16SZ, &iov[2]);
- evConsIovec((void*)buf2, buflen2, &iov[3]);
- niov = 4;
- explen += INT16SZ + buflen2;
- }
- if (TEMP_FAILURE_RETRY (writev(statp->_vcsock, iov, niov)) != explen) {
- *terrno = errno;
- return close_and_return_error (statp, resplen2);
- }
- /*
- * Receive length & response
- */
- int recvresp1 = 0;
- /* Skip the second response if there is no second query.
- To do that we mark the second response as received. */
- int recvresp2 = buf2 == NULL;
- uint16_t rlen16;
- read_len:
- cp = (u_char *)&rlen16;
- len = sizeof(rlen16);
- while ((n = TEMP_FAILURE_RETRY (read(statp->_vcsock, cp,
- (int)len))) > 0) {
- cp += n;
- if ((len -= n) <= 0)
- break;
- }
- if (n <= 0) {
- *terrno = errno;
- /*
- * A long running process might get its TCP
- * connection reset if the remote server was
- * restarted. Requery the server instead of
- * trying a new one. When there is only one
- * server, this means that a query might work
- * instead of failing. We only allow one reset
- * per query to prevent looping.
- */
- if (*terrno == ECONNRESET && !connreset)
- {
- __res_iclose (statp, false);
- connreset = 1;
- goto same_ns;
- }
- return close_and_return_error (statp, resplen2);
- }
- int rlen = ntohs (rlen16);
- int *thisanssizp;
- u_char **thisansp;
- int *thisresplenp;
- if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
- /* We have not received any responses
- yet or we only have one response to
- receive. */
- thisanssizp = anssizp;
- thisansp = anscp ?: ansp;
- assert (anscp != NULL || ansp2 == NULL);
- thisresplenp = &resplen;
- } else {
- thisanssizp = anssizp2;
- thisansp = ansp2;
- thisresplenp = resplen2;
- }
- anhp = (HEADER *) *thisansp;
- *thisresplenp = rlen;
- /* Is the answer buffer too small? */
- if (*thisanssizp < rlen) {
- /* If the current buffer is not the the static
- user-supplied buffer then we can reallocate
- it. */
- if (thisansp != NULL && thisansp != ansp) {
- /* Always allocate MAXPACKET, callers expect
- this specific size. */
- u_char *newp = malloc (MAXPACKET);
- if (newp == NULL)
- {
- *terrno = ENOMEM;
- return close_and_return_error (statp, resplen2);
- }
- *thisanssizp = MAXPACKET;
- *thisansp = newp;
- if (thisansp == ansp2)
- *ansp2_malloced = 1;
- anhp = (HEADER *) newp;
- /* A uint16_t can't be larger than MAXPACKET
- thus it's safe to allocate MAXPACKET but
- read RLEN bytes instead. */
- len = rlen;
- } else {
- truncating = 1;
- len = *thisanssizp;
- }
- } else
- len = rlen;
- if (__glibc_unlikely (len < HFIXEDSZ)) {
- /*
- * Undersized message.
- */
- *terrno = EMSGSIZE;
- return close_and_return_error (statp, resplen2);
- }
- cp = *thisansp;
- while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){
- cp += n;
- len -= n;
- }
- if (__glibc_unlikely (n <= 0)) {
- *terrno = errno;
- return close_and_return_error (statp, resplen2);
- }
- if (__glibc_unlikely (truncating)) {
- /*
- * Flush rest of answer so connection stays in synch.
- */
- anhp->tc = 1;
- len = rlen - *thisanssizp;
- while (len != 0) {
- char junk[PACKETSZ];
- n = read(statp->_vcsock, junk,
- (len > sizeof junk) ? sizeof junk : len);
- if (n > 0)
- len -= n;
- else
- break;
- }
- }
- /*
- * If the calling application has bailed out of
- * a previous call and failed to arrange to have
- * the circuit closed or the server has got
- * itself confused, then drop the packet and
- * wait for the correct one.
- */
- if ((recvresp1 || hp->id != anhp->id)
- && (recvresp2 || hp2->id != anhp->id))
- goto read_len;
- /* Mark which reply we received. */
- if (recvresp1 == 0 && hp->id == anhp->id)
- recvresp1 = 1;
- else
- recvresp2 = 1;
- /* Repeat waiting if we have a second answer to arrive. */
- if ((recvresp1 & recvresp2) == 0)
- goto read_len;
- /*
- * All is well, or the error is fatal. Signal that the
- * next nameserver ought not be tried.
- */
- return resplen;
- }
- static int
- reopen (res_state statp, int *terrno, int ns)
- {
- if (EXT(statp).nssocks[ns] == -1) {
- struct sockaddr *nsap = get_nsaddr (statp, ns);
- socklen_t slen;
- /* only try IPv6 if IPv6 NS and if not failed before */
- if (nsap->sa_family == AF_INET6 && !statp->ipv6_unavail) {
- EXT(statp).nssocks[ns] = socket
- (PF_INET6,
- SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
- if (EXT(statp).nssocks[ns] < 0)
- statp->ipv6_unavail = errno == EAFNOSUPPORT;
- slen = sizeof (struct sockaddr_in6);
- } else if (nsap->sa_family == AF_INET) {
- EXT(statp).nssocks[ns] = socket
- (PF_INET,
- SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
- slen = sizeof (struct sockaddr_in);
- }
- if (EXT(statp).nssocks[ns] < 0) {
- *terrno = errno;
- return (-1);
- }
- /*
- * On a 4.3BSD+ machine (client and server,
- * actually), sending to a nameserver datagram
- * port with no nameserver will cause an
- * ICMP port unreachable message to be returned.
- * If our datagram socket is "connected" to the
- * server, we get an ECONNREFUSED error on the next
- * socket operation, and select returns if the
- * error message is received. We can thus detect
- * the absence of a nameserver without timing out.
- */
- /* With GCC 5.3 when compiling with -Os the compiler
- emits a warning that slen may be used uninitialized,
- but that is never true. Both slen and
- EXT(statp).nssocks[ns] are initialized together or
- the function return -1 before control flow reaches
- the call to connect with slen. */
- DIAG_PUSH_NEEDS_COMMENT;
- DIAG_IGNORE_Os_NEEDS_COMMENT (5, "-Wmaybe-uninitialized");
- if (connect(EXT(statp).nssocks[ns], nsap, slen) < 0) {
- DIAG_POP_NEEDS_COMMENT;
- __res_iclose(statp, false);
- return (0);
- }
- }
- return 1;
- }
- /* The send_dg function is responsible for sending a DNS query over UDP
- to the nameserver numbered NS from the res_state STATP i.e.
- EXT(statp).nssocks[ns]. The function supports IPv4 and IPv6 queries
- along with the ability to send the query in parallel for both stacks
- (default) or serially (RES_SINGLKUP). It also supports serial lookup
- with a close and reopen of the socket used to talk to the server
- (RES_SNGLKUPREOP) to work around broken name servers.
- The query stored in BUF of BUFLEN length is sent first followed by
- the query stored in BUF2 of BUFLEN2 length. Queries are sent
- in parallel (default) or serially (RES_SINGLKUP or RES_SNGLKUPREOP).
- Answers to the query are stored firstly in *ANSP up to a max of
- *ANSSIZP bytes. If more than *ANSSIZP bytes are needed and ANSCP
- is non-NULL (to indicate that modifying the answer buffer is allowed)
- then malloc is used to allocate a new response buffer and ANSCP and
- ANSP will both point to the new buffer. If more than *ANSSIZP bytes
- are needed but ANSCP is NULL, then as much of the response as
- possible is read into the buffer, but the results will be truncated.
- When truncation happens because of a small answer buffer the DNS
- packets header field TC will bet set to 1, indicating a truncated
- message, while the rest of the UDP packet is discarded.
- Answers to the query are stored secondly in *ANSP2 up to a max of
- *ANSSIZP2 bytes, with the actual response length stored in
- *RESPLEN2. If more than *ANSSIZP bytes are needed and ANSP2
- is non-NULL (required for a second query) then malloc is used to
- allocate a new response buffer, *ANSSIZP2 is set to the new buffer
- size and *ANSP2_MALLOCED is set to 1.
- The ANSP2_MALLOCED argument will eventually be removed as the
- change in buffer pointer can be used to detect the buffer has
- changed and that the caller should use free on the new buffer.
- Note that the answers may arrive in any order from the server and
- therefore the first and second answer buffers may not correspond to
- the first and second queries.
- It is not supported to call this function with a non-NULL ANSP2
- but a NULL ANSCP. Put another way, you can call send_vc with a
- single unmodifiable buffer or two modifiable buffers, but no other
- combination is supported.
- It is the caller's responsibility to free the malloc allocated
- buffers by detecting that the pointers have changed from their
- original values i.e. *ANSCP or *ANSP2 has changed.
- If an answer is truncated because of UDP datagram DNS limits then
- *V_CIRCUIT is set to 1 and the return value non-zero to indicate to
- the caller to retry with TCP. The value *GOTSOMEWHERE is set to 1
- if any progress was made reading a response from the nameserver and
- is used by the caller to distinguish between ECONNREFUSED and
- ETIMEDOUT (the latter if *GOTSOMEWHERE is 1).
- If errors are encountered then *TERRNO is set to an appropriate
- errno value and a zero result is returned for a recoverable error,
- and a less-than zero result is returned for a non-recoverable error.
- If no errors are encountered then *TERRNO is left unmodified and
- a the length of the first response in bytes is returned. */
- static int
- send_dg(res_state statp,
- const u_char *buf, int buflen, const u_char *buf2, int buflen2,
- u_char **ansp, int *anssizp,
- int *terrno, int ns, int *v_circuit, int *gotsomewhere, u_char **anscp,
- u_char **ansp2, int *anssizp2, int *resplen2, int *ansp2_malloced)
- {
- const HEADER *hp = (HEADER *) buf;
- const HEADER *hp2 = (HEADER *) buf2;
- struct timespec now, timeout, finish;
- struct pollfd pfd[1];
- int ptimeout;
- struct sockaddr_in6 from;
- int resplen = 0;
- int n;
- /*
- * Compute time for the total operation.
- */
- int seconds = (statp->retrans << ns);
- if (ns > 0)
- seconds /= statp->nscount;
- if (seconds <= 0)
- seconds = 1;
- bool single_request_reopen = (statp->options & RES_SNGLKUPREOP) != 0;
- bool single_request = (((statp->options & RES_SNGLKUP) != 0)
- | single_request_reopen);
- int save_gotsomewhere = *gotsomewhere;
- int retval;
- retry_reopen:
- retval = reopen (statp, terrno, ns);
- if (retval <= 0)
- {
- if (resplen2 != NULL)
- *resplen2 = 0;
- return retval;
- }
- retry:
- evNowTime(&now);
- evConsTime(&timeout, seconds, 0);
- evAddTime(&finish, &now, &timeout);
- int need_recompute = 0;
- int nwritten = 0;
- int recvresp1 = 0;
- /* Skip the second response if there is no second query.
- To do that we mark the second response as received. */
- int recvresp2 = buf2 == NULL;
- pfd[0].fd = EXT(statp).nssocks[ns];
- pfd[0].events = POLLOUT;
- wait:
- if (need_recompute) {
- recompute_resend:
- evNowTime(&now);
- if (evCmpTime(finish, now) <= 0) {
- poll_err_out:
- return close_and_return_error (statp, resplen2);
- }
- evSubTime(&timeout, &finish, &now);
- need_recompute = 0;
- }
- /* Convert struct timespec in milliseconds. */
- ptimeout = timeout.tv_sec * 1000 + timeout.tv_nsec / 1000000;
- n = 0;
- if (nwritten == 0)
- n = __poll (pfd, 1, 0);
- if (__glibc_unlikely (n == 0)) {
- n = __poll (pfd, 1, ptimeout);
- need_recompute = 1;
- }
- if (n == 0) {
- if (resplen > 1 && (recvresp1 || (buf2 != NULL && recvresp2)))
- {
- /* There are quite a few broken name servers out
- there which don't handle two outstanding
- requests from the same source. There are also
- broken firewall settings. If we time out after
- having received one answer switch to the mode
- where we send the second request only once we
- have received the first answer. */
- if (!single_request)
- {
- statp->options |= RES_SNGLKUP;
- single_request = true;
- *gotsomewhere = save_gotsomewhere;
- goto retry;
- }
- else if (!single_request_reopen)
- {
- statp->options |= RES_SNGLKUPREOP;
- single_request_reopen = true;
- *gotsomewhere = save_gotsomewhere;
- __res_iclose (statp, false);
- goto retry_reopen;
- }
- *resplen2 = 1;
- return resplen;
- }
- *gotsomewhere = 1;
- if (resplen2 != NULL)
- *resplen2 = 0;
- return 0;
- }
- if (n < 0) {
- if (errno == EINTR)
- goto recompute_resend;
- goto poll_err_out;
- }
- __set_errno (0);
- if (pfd[0].revents & POLLOUT) {
- #ifndef __ASSUME_SENDMMSG
- static int have_sendmmsg;
- #else
- # define have_sendmmsg 1
- #endif
- if (have_sendmmsg >= 0 && nwritten == 0 && buf2 != NULL
- && !single_request)
- {
- struct iovec iov =
- { .iov_base = (void *) buf, .iov_len = buflen };
- struct iovec iov2 =
- { .iov_base = (void *) buf2, .iov_len = buflen2 };
- struct mmsghdr reqs[2] =
- {
- {
- .msg_hdr =
- {
- .msg_iov = &iov,
- .msg_iovlen = 1,
- },
- },
- {
- .msg_hdr =
- {
- .msg_iov = &iov2,
- .msg_iovlen = 1,
- }
- },
- };
- int ndg = __sendmmsg (pfd[0].fd, reqs, 2, MSG_NOSIGNAL);
- if (__glibc_likely (ndg == 2))
- {
- if (reqs[0].msg_len != buflen
- || reqs[1].msg_len != buflen2)
- goto fail_sendmmsg;
- pfd[0].events = POLLIN;
- nwritten += 2;
- }
- else if (ndg == 1 && reqs[0].msg_len == buflen)
- goto just_one;
- else if (ndg < 0 && (errno == EINTR || errno == EAGAIN))
- goto recompute_resend;
- else
- {
- #ifndef __ASSUME_SENDMMSG
- if (__glibc_unlikely (have_sendmmsg == 0))
- {
- if (ndg < 0 && errno == ENOSYS)
- {
- have_sendmmsg = -1;
- goto try_send;
- }
- have_sendmmsg = 1;
- }
- #endif
- fail_sendmmsg:
- return close_and_return_error (statp, resplen2);
- }
- }
- else
- {
- ssize_t sr;
- #ifndef __ASSUME_SENDMMSG
- try_send:
- #endif
- if (nwritten != 0)
- sr = send (pfd[0].fd, buf2, buflen2, MSG_NOSIGNAL);
- else
- sr = send (pfd[0].fd, buf, buflen, MSG_NOSIGNAL);
- if (sr != (nwritten != 0 ? buflen2 : buflen)) {
- if (errno == EINTR || errno == EAGAIN)
- goto recompute_resend;
- return close_and_return_error (statp, resplen2);
- }
- just_one:
- if (nwritten != 0 || buf2 == NULL || single_request)
- pfd[0].events = POLLIN;
- else
- pfd[0].events = POLLIN | POLLOUT;
- ++nwritten;
- }
- goto wait;
- } else if (pfd[0].revents & POLLIN) {
- int *thisanssizp;
- u_char **thisansp;
- int *thisresplenp;
- if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
- /* We have not received any responses
- yet or we only have one response to
- receive. */
- thisanssizp = anssizp;
- thisansp = anscp ?: ansp;
- assert (anscp != NULL || ansp2 == NULL);
- thisresplenp = &resplen;
- } else {
- thisanssizp = anssizp2;
- thisansp = ansp2;
- thisresplenp = resplen2;
- }
- if (*thisanssizp < MAXPACKET
- /* If the current buffer is not the the static
- user-supplied buffer then we can reallocate
- it. */
- && (thisansp != NULL && thisansp != ansp)
- #ifdef FIONREAD
- /* Is the size too small? */
- && (ioctl (pfd[0].fd, FIONREAD, thisresplenp) < 0
- || *thisanssizp < *thisresplenp)
- #endif
- ) {
- /* Always allocate MAXPACKET, callers expect
- this specific size. */
- u_char *newp = malloc (MAXPACKET);
- if (newp != NULL) {
- *thisanssizp = MAXPACKET;
- *thisansp = newp;
- if (thisansp == ansp2)
- *ansp2_malloced = 1;
- }
- }
- /* We could end up with truncation if anscp was NULL
- (not allowed to change caller's buffer) and the
- response buffer size is too small. This isn't a
- reliable way to detect truncation because the ioctl
- may be an inaccurate report of the UDP message size.
- Therefore we use this only to issue debug output.
- To do truncation accurately with UDP we need
- MSG_TRUNC which is only available on Linux. We
- can abstract out the Linux-specific feature in the
- future to detect truncation. */
- HEADER *anhp = (HEADER *) *thisansp;
- socklen_t fromlen = sizeof(struct sockaddr_in6);
- assert (sizeof(from) <= fromlen);
- *thisresplenp = recvfrom(pfd[0].fd, (char*)*thisansp,
- *thisanssizp, 0,
- (struct sockaddr *)&from, &fromlen);
- if (__glibc_unlikely (*thisresplenp <= 0)) {
- if (errno == EINTR || errno == EAGAIN) {
- need_recompute = 1;
- goto wait;
- }
- return close_and_return_error (statp, resplen2);
- }
- *gotsomewhere = 1;
- if (__glibc_unlikely (*thisresplenp < HFIXEDSZ)) {
- /*
- * Undersized message.
- */
- *terrno = EMSGSIZE;
- return close_and_return_error (statp, resplen2);
- }
- if ((recvresp1 || hp->id != anhp->id)
- && (recvresp2 || hp2->id != anhp->id)) {
- /*
- * response from old query, ignore it.
- * XXX - potential security hazard could
- * be detected here.
- */
- goto wait;
- }
- if (!(statp->options & RES_INSECURE1) &&
- !res_ourserver_p(statp, &from)) {
- /*
- * response from wrong server? ignore it.
- * XXX - potential security hazard could
- * be detected here.
- */
- goto wait;
- }
- if (!(statp->options & RES_INSECURE2)
- && (recvresp1 || !res_queriesmatch(buf, buf + buflen,
- *thisansp,
- *thisansp
- + *thisanssizp))
- && (recvresp2 || !res_queriesmatch(buf2, buf2 + buflen2,
- *thisansp,
- *thisansp
- + *thisanssizp))) {
- /*
- * response contains wrong query? ignore it.
- * XXX - potential security hazard could
- * be detected here.
- */
- goto wait;
- }
- if (anhp->rcode == SERVFAIL ||
- anhp->rcode == NOTIMP ||
- anhp->rcode == REFUSED) {
- next_ns:
- if (recvresp1 || (buf2 != NULL && recvresp2)) {
- *resplen2 = 0;
- return resplen;
- }
- if (buf2 != NULL)
- {
- /* No data from the first reply. */
- resplen = 0;
- /* We are waiting for a possible second reply. */
- if (hp->id == anhp->id)
- recvresp1 = 1;
- else
- recvresp2 = 1;
- goto wait;
- }
- /* don't retry if called from dig */
- if (!statp->pfcode)
- return close_and_return_error (statp, resplen2);
- __res_iclose(statp, false);
- }
- if (anhp->rcode == NOERROR && anhp->ancount == 0
- && anhp->aa == 0 && anhp->ra == 0 && anhp->arcount == 0) {
- goto next_ns;
- }
- if (!(statp->options & RES_IGNTC) && anhp->tc) {
- /*
- * To get the rest of answer,
- * use TCP with same server.
- */
- *v_circuit = 1;
- __res_iclose(statp, false);
- // XXX if we have received one reply we could
- // XXX use it and not repeat it over TCP...
- if (resplen2 != NULL)
- *resplen2 = 0;
- return (1);
- }
- /* Mark which reply we received. */
- if (recvresp1 == 0 && hp->id == anhp->id)
- recvresp1 = 1;
- else
- recvresp2 = 1;
- /* Repeat waiting if we have a second answer to arrive. */
- if ((recvresp1 & recvresp2) == 0) {
- if (single_request) {
- pfd[0].events = POLLOUT;
- if (single_request_reopen) {
- __res_iclose (statp, false);
- retval = reopen (statp, terrno, ns);
- if (retval <= 0)
- {
- if (resplen2 != NULL)
- *resplen2 = 0;
- return retval;
- }
- pfd[0].fd = EXT(statp).nssocks[ns];
- }
- }
- goto wait;
- }
- /* All is well. We have received both responses (if
- two responses were requested). */
- return (resplen);
- } else if (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL))
- /* Something went wrong. We can stop trying. */
- return close_and_return_error (statp, resplen2);
- else {
- /* poll should not have returned > 0 in this case. */
- abort ();
- }
- }
- static int
- sock_eq(struct sockaddr_in6 *a1, struct sockaddr_in6 *a2) {
- if (a1->sin6_family == a2->sin6_family) {
- if (a1->sin6_family == AF_INET)
- return ((((struct sockaddr_in *)a1)->sin_port ==
- ((struct sockaddr_in *)a2)->sin_port) &&
- (((struct sockaddr_in *)a1)->sin_addr.s_addr ==
- ((struct sockaddr_in *)a2)->sin_addr.s_addr));
- else
- return ((a1->sin6_port == a2->sin6_port) &&
- !memcmp(&a1->sin6_addr, &a2->sin6_addr,
- sizeof (struct in6_addr)));
- }
- if (a1->sin6_family == AF_INET) {
- struct sockaddr_in6 *sap = a1;
- a1 = a2;
- a2 = sap;
- } /* assumes that AF_INET and AF_INET6 are the only possibilities */
- return ((a1->sin6_port == ((struct sockaddr_in *)a2)->sin_port) &&
- IN6_IS_ADDR_V4MAPPED(&a1->sin6_addr) &&
- (a1->sin6_addr.s6_addr32[3] ==
- ((struct sockaddr_in *)a2)->sin_addr.s_addr));
- }
|