Back to index

glibc  2.9
Defines | Functions
res_send.c File Reference
#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.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "res_debug.h"

Go to the source code of this file.

Defines

#define MAXPACKET   65536
#define BILLION   1000000000
#define EXT(res)   ((res)->_u._ext)

Functions

static void __attribute ((always_inline))
static void evConsTime (struct timespec *res, time_t sec, long nsec)
static void evAddTime (struct timespec *res, const struct timespec *addend1, const struct timespec *addend2)
static void evSubTime (struct timespec *res, const struct timespec *minuend, const struct timespec *subtrahend)
static int evCmpTime (struct timespec a, struct timespec b)
static void evNowTime (struct timespec *res)
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 *)
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 *)
static int sock_eq (struct sockaddr_in6 *, struct sockaddr_in6 *)
static void convaddr4to6 (struct sockaddr_in6 *sa)
int res_ourserver_p (const res_state statp, const struct sockaddr_in6 *inp)
int res_nameinquery (const char *name, int type, int class, const u_char *buf, const u_char *eom)
 libresolv_hidden_def (res_nameinquery)
 libresolv_hidden_def (res_queriesmatch)
int res_nsend (res_state statp, const u_char *buf, int buflen, u_char *ans, int anssiz)
 libresolv_hidden_def (res_nsend)

Define Documentation

#define BILLION   1000000000

Definition at line 118 of file res_send.c.

#define EXT (   res)    ((res)->_u._ext)

Definition at line 174 of file res_send.c.

#define MAXPACKET   65536

Definition at line 102 of file res_send.c.


Function Documentation

static void __attribute ( (always_inline)  ) [inline, static]

Definition at line 109 of file res_send.c.

                                                      {
       memset(vec, 0xf5, sizeof (*vec));
       vec->iov_base = buf;
       vec->iov_len = cnt;
}
static void convaddr4to6 ( struct sockaddr_in6 sa) [static]

Definition at line 1339 of file res_send.c.

{
    struct sockaddr_in *sa4p = (struct sockaddr_in *) sa;
    in_port_t port = sa4p->sin_port;
    in_addr_t addr = sa4p->sin_addr.s_addr;

    sa->sin6_family = AF_INET6;
    sa->sin6_port = port;
    sa->sin6_addr.s6_addr32[0] = 0;
    sa->sin6_addr.s6_addr32[1] = 0;
    sa->sin6_addr.s6_addr32[2] = htonl(0xFFFF);
    sa->sin6_addr.s6_addr32[3] = addr;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void evAddTime ( struct timespec res,
const struct timespec addend1,
const struct timespec addend2 
) [inline, static]

Definition at line 127 of file res_send.c.

                                         {
       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;
       }
}

Here is the caller graph for this function:

static int evCmpTime ( struct timespec  a,
struct timespec  b 
) [inline, static]

Definition at line 151 of file res_send.c.

                                                {
       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));
}

Here is the caller graph for this function:

static void evConsTime ( struct timespec res,
time_t  sec,
long  nsec 
) [inline, static]

Definition at line 121 of file res_send.c.

                                                        {
       res->tv_sec = sec;
       res->tv_nsec = nsec;
}

Here is the caller graph for this function:

static void evNowTime ( struct timespec res) [inline, static]

Definition at line 160 of file res_send.c.

                                {
       struct timeval now;

       if (gettimeofday(&now, NULL) < 0)
              evConsTime(res, 0, 0);
       else
              TIMEVAL_TO_TIMESPEC (&now, res);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void evSubTime ( struct timespec res,
const struct timespec minuend,
const struct timespec subtrahend 
) [inline, static]

Definition at line 138 of file res_send.c.

                                            {
       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--;
       }
}

Here is the caller graph for this function:

Definition at line 281 of file res_send.c.

{
       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);
}

Here is the call graph for this function:

Definition at line 336 of file res_send.c.

{
  int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;

       if (statp->nscount == 0) {
              __set_errno (ESRCH);
              return (-1);
       }

       if (anssiz < (buf2 == NULL ? 1 : 2) * HFIXEDSZ) {
              __set_errno (EINVAL);
              return (-1);
       }

#ifdef USE_HOOKS
       if (__builtin_expect (statp->qhook || statp->rhook, 0)) {
              if (anssiz < MAXPACKET && ansp) {
                     u_char *buf = malloc (MAXPACKET);
                     if (buf == NULL)
                            return (-1);
                     memcpy (buf, ans, HFIXEDSZ);
                     *ansp = buf;
                     ans = buf;
                     anssiz = MAXPACKET;
              }
       }
#endif

       DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
              (stdout, ";; res_send()\n"), buf, buflen);
       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).nsinit) {
              int needclose = 0;

              if (EXT(statp).nscount != statp->nscount)
                     needclose++;
              else
                     for (ns = 0; ns < MAXNS; ns++) {
                            unsigned int map = EXT(statp).nsmap[ns];
                            if (map < MAXNS
                                && !sock_eq((struct sockaddr_in6 *)
                                          &statp->nsaddr_list[map],
                                          EXT(statp).nsaddrs[ns]))
                            {
                                   needclose++;
                                   break;
                            }
                     }
              if (needclose)
                     __res_iclose(statp, false);
       }

       /*
        * Maybe initialize our private copy of the ns_addr_list.
        */
       if (EXT(statp).nsinit == 0) {
              unsigned char map[MAXNS];

              memset (map, MAXNS, sizeof (map));
              for (n = 0; n < MAXNS; n++) {
                     ns = EXT(statp).nsmap[n];
                     if (ns < statp->nscount)
                            map[ns] = n;
                     else if (ns < MAXNS) {
                            free(EXT(statp).nsaddrs[n]);
                            EXT(statp).nsaddrs[n] = NULL;
                            EXT(statp).nsmap[n] = MAXNS;
                     }
              }
              n = statp->nscount;
              if (statp->nscount > EXT(statp).nscount)
                     for (n = EXT(statp).nscount, ns = 0;
                          n < statp->nscount; n++) {
                            while (ns < MAXNS
                                   && EXT(statp).nsmap[ns] != MAXNS)
                                   ns++;
                            if (ns == MAXNS)
                                   break;
                            EXT(statp).nsmap[ns] = n;
                            map[n] = ns++;
                     }
              EXT(statp).nscount = n;
              for (ns = 0; ns < EXT(statp).nscount; ns++) {
                     n = map[ns];
                     if (EXT(statp).nsaddrs[n] == NULL)
                            EXT(statp).nsaddrs[n] =
                                malloc(sizeof (struct sockaddr_in6));
                     if (EXT(statp).nsaddrs[n] != NULL) {
                            memset (mempcpy(EXT(statp).nsaddrs[n],
                                          &statp->nsaddr_list[ns],
                                          sizeof (struct sockaddr_in)),
                                   '\0',
                                   sizeof (struct sockaddr_in6)
                                   - sizeof (struct sockaddr_in));
                            EXT(statp).nssocks[n] = -1;
                            n++;
                     }
              }
              EXT(statp).nsinit = 1;
       }

       /*
        * Some resolvers want to even out the load on their nameservers.
        * Note that RES_BLAST overrides RES_ROTATE.
        */
       if (__builtin_expect ((statp->options & RES_ROTATE) != 0, 0) &&
           (statp->options & RES_BLAST) == 0) {
              struct sockaddr_in6 *ina;
              unsigned int map;

              n = 0;
              while (n < MAXNS && EXT(statp).nsmap[n] == MAXNS)
                     n++;
              if (n < MAXNS) {
                     ina = EXT(statp).nsaddrs[n];
                     map = EXT(statp).nsmap[n];
                     for (;;) {
                            ns = n + 1;
                            while (ns < MAXNS
                                   && EXT(statp).nsmap[ns] == MAXNS)
                                   ns++;
                            if (ns == MAXNS)
                                   break;
                            EXT(statp).nsaddrs[n] = EXT(statp).nsaddrs[ns];
                            EXT(statp).nsmap[n] = EXT(statp).nsmap[ns];
                            n = ns;
                     }
                     EXT(statp).nsaddrs[n] = ina;
                     EXT(statp).nsmap[n] = map;
              }
       }

       /*
        * Send request, RETRY times, or until successful.
        */
       for (try = 0; try < statp->retry; try++) {
           for (ns = 0; ns < MAXNS; ns++)
           {
              struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];

              if (nsap == NULL)
                     goto next_ns;
           same_ns:
#ifdef USE_HOOKS
              if (__builtin_expect (statp->qhook != NULL, 0)) {
                     int done = 0, loops = 0;

                     do {
                            res_sendhookact act;

                            struct sockaddr_in *nsap4;
                            nsap4 = (struct sockaddr_in *) nsap;
                            act = (*statp->qhook)(&nsap4, &buf, &buflen,
                                                ans, anssiz, &resplen);
                            nsap = (struct sockaddr_in6 *) nsap4;
                            switch (act) {
                            case res_goahead:
                                   done = 1;
                                   break;
                            case res_nextns:
                                   __res_iclose(statp, false);
                                   goto next_ns;
                            case res_done:
                                   return (resplen);
                            case res_modified:
                                   /* give the hook another try */
                                   if (++loops < 42) /*doug adams*/
                                          break;
                                   /*FALLTHROUGH*/
                            case res_error:
                                   /*FALLTHROUGH*/
                            default:
                                   return (-1);
                            }
                     } while (!done);
              }
#endif

#ifdef DEBUG
              char tmpbuf[40];
#endif
              Dprint(statp->options & RES_DEBUG,
                     (stdout, ";; Querying server (# %d) address = %s\n",
                     ns + 1, inet_ntop(AF_INET6, &nsap->sin6_addr,
                                     tmpbuf, sizeof (tmpbuf))));

              if (__builtin_expect (v_circuit, 0)) {
                     /* 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);
                     if (n < 0)
                            return (-1);
                     if (n == 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);
                     if (n < 0)
                            return (-1);
                     if (n == 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;

              Dprint((statp->options & RES_DEBUG) ||
                     ((statp->pfcode & RES_PRF_REPLY) &&
                     (statp->pfcode & RES_PRF_HEAD1)),
                     (stdout, ";; got answer:\n"));

              DprintQ((statp->options & RES_DEBUG) ||
                     (statp->pfcode & RES_PRF_REPLY),
                     (stdout, "%s", ""),
                     ans, (resplen > anssiz) ? anssiz : resplen);
              if (buf2 != NULL)
                DprintQ((statp->options & RES_DEBUG) ||
                       (statp->pfcode & RES_PRF_REPLY),
                       (stdout, "%s", ""),
                       *ansp2, (*resplen2 > *nansp2) ? *nansp2 : *resplen2);

              /*
               * 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);
              }
#ifdef USE_HOOKS
              if (__builtin_expect (statp->rhook, 0)) {
                     int done = 0, loops = 0;

                     do {
                            res_sendhookact act;

                            act = (*statp->rhook)((struct sockaddr_in *)
                                                nsap, buf, buflen,
                                                ans, anssiz, &resplen);
                            switch (act) {
                            case res_goahead:
                            case res_done:
                                   done = 1;
                                   break;
                            case res_nextns:
                                   __res_iclose(statp, false);
                                   goto next_ns;
                            case res_modified:
                                   /* give the hook another try */
                                   if (++loops < 42) /*doug adams*/
                                          break;
                                   /*FALLTHROUGH*/
                            case res_error:
                                   /*FALLTHROUGH*/
                            default:
                                   return (-1);
                            }
                     } while (!done);

              }
#endif
              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);
}

Here is the call graph for this function:

Definition at line 643 of file res_send.c.

{
       const HEADER *hp = (HEADER *) buf;
       const HEADER *hp2 = (HEADER *) buf2;
       u_char *ans = *ansp;
       int orig_anssizp = *anssizp;
       // XXX REMOVE
       // int anssiz = *anssizp;
       HEADER *anhp = (HEADER *) ans;
       struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
       int truncating, connreset, resplen, n;
       struct iovec iov[4];
       u_short len;
       u_short len2;
       u_char *cp;

       if (resplen2 != NULL)
         *resplen2 = 0;
       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, 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->sin6_family, SOCK_STREAM, 0);
              if (statp->_vcsock < 0) {
                     *terrno = errno;
                     Perror(statp, stderr, "socket(vc)", errno);
                     return (-1);
              }
              __set_errno (0);
              if (connect(statp->_vcsock, (struct sockaddr *)nsap,
                         nsap->sin6_family == AF_INET
                         ? sizeof (struct sockaddr_in)
                         : sizeof (struct sockaddr_in6)) < 0) {
                     *terrno = errno;
                     Aerror(statp, stderr, "connect/vc", errno,
                            (struct sockaddr *) nsap);
                     __res_iclose(statp, false);
                     return (0);
              }
              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;
              Perror(statp, stderr, "write failed", errno);
              __res_iclose(statp, false);
              return (0);
       }
       /*
        * Receive length & response
        */
       int recvresp1 = 0;
       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;
              Perror(statp, stderr, "read failed", errno);
              __res_iclose(statp, false);
              /*
               * 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) {
                     connreset = 1;
                     goto same_ns;
              }
              return (0);
       }
       int rlen = ntohs (rlen16);

       int *thisanssizp;
       u_char **thisansp;
       int *thisresplenp;
       if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
              thisanssizp = anssizp;
              thisansp = anscp ?: ansp;
              assert (anscp != NULL || ansp2 == NULL);
              thisresplenp = &resplen;
       } else {
              if (*anssizp != MAXPACKET) {
                     /* No buffer allocated for the first
                        reply.  We can try to use the rest
                        of the user-provided buffer.  */
#ifdef _STRING_ARCH_unaligned
                     *anssizp2 = orig_anssizp - resplen;
                     *ansp2 = *ansp + resplen;
#else
                     int aligned_resplen
                       = ((resplen + __alignof__ (HEADER) - 1)
                          & ~(__alignof__ (HEADER) - 1));
                     *anssizp2 = orig_anssizp - aligned_resplen;
                     *ansp2 = *ansp + aligned_resplen;
#endif
              } else {
                     /* The first reply did not fit into the
                        user-provided buffer.  Maybe the second
                        answer will.  */
                     *anssizp2 = orig_anssizp;
                     *ansp2 = *ansp;
              }

              thisanssizp = anssizp2;
              thisansp = ansp2;
              thisresplenp = resplen2;
       }
       anhp = (HEADER *) *thisansp;

       *thisresplenp = rlen;
       if (rlen > *thisanssizp) {
              /* Yes, we test ANSCP here.  If we have two buffers
                 both will be allocatable.  */
              if (__builtin_expect (anscp != NULL, 1)) {
                     u_char *newp = malloc (MAXPACKET);
                     if (newp == NULL) {
                            *terrno = ENOMEM;
                            __res_iclose(statp, false);
                            return (0);
                     }
                     *thisanssizp = MAXPACKET;
                     *thisansp = newp;
                     anhp = (HEADER *) newp;
                     len = rlen;
              } else {
                     Dprint(statp->options & RES_DEBUG,
                            (stdout, ";; response truncated\n")
                     );
                     truncating = 1;
                     len = *thisanssizp;
              }
       } else
              len = rlen;

       if (__builtin_expect (len < HFIXEDSZ, 0)) {
              /*
               * Undersized message.
               */
              Dprint(statp->options & RES_DEBUG,
                     (stdout, ";; undersized: %d\n", len));
              *terrno = EMSGSIZE;
              __res_iclose(statp, false);
              return (0);
       }

       cp = *thisansp;
       while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){
              cp += n;
              len -= n;
       }
       if (__builtin_expect (n <= 0, 0)) {
              *terrno = errno;
              Perror(statp, stderr, "read(vc)", errno);
              __res_iclose(statp, false);
              return (0);
       }
       if (__builtin_expect (truncating, 0)) {
              /*
               * 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 applicating 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)) {
              DprintQ((statp->options & RES_DEBUG) ||
                     (statp->pfcode & RES_PRF_REPLY),
                     (stdout, ";; old answer (unexpected):\n"),
                     *thisansp,
                     (rlen > *thisanssiz) ? *thisanssiz: rlen);
              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;
}

Here is the call graph for this function:

int res_nameinquery ( const char *  name,
int  type,
int  class,
const u_char buf,
const u_char eom 
)

Definition at line 257 of file res_send.c.

{
       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);
}

Here is the call graph for this function:

int res_nsend ( res_state  statp,
const u_char buf,
int  buflen,
u_char ans,
int  anssiz 
)

Definition at line 637 of file res_send.c.

{
  return __libc_res_nsend(statp, buf, buflen, NULL, 0, ans, anssiz,
                       NULL, NULL, NULL, NULL);
}
int res_ourserver_p ( const res_state  statp,
const struct sockaddr_in6 inp 
)

Definition at line 210 of file res_send.c.

{
       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 < MAXNS;  ns++) {
                const struct sockaddr_in *srv =
                  (struct sockaddr_in *)EXT(statp).nsaddrs[ns];

                if ((srv != NULL) && (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 < MAXNS;  ns++) {
                const struct sockaddr_in6 *srv = EXT(statp).nsaddrs[ns];
                if ((srv != NULL) && (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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

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 
) [static]

Definition at line 903 of file res_send.c.

{
       const HEADER *hp = (HEADER *) buf;
       const HEADER *hp2 = (HEADER *) buf2;
       u_char *ans = *ansp;
       int orig_anssizp = *anssizp;
       struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
       struct timespec now, timeout, finish;
       struct pollfd pfd[1];
        int ptimeout;
       struct sockaddr_in6 from;
       int resplen, seconds, n;

       if (EXT(statp).nssocks[ns] == -1) {
              /* only try IPv6 if IPv6 NS and if not failed before */
              if ((EXT(statp).nscount6 > 0) && !statp->ipv6_unavail) {
                     EXT(statp).nssocks[ns] =
                         socket(PF_INET6, SOCK_DGRAM, 0);
                     if (EXT(statp).nssocks[ns] < 0)
                         statp->ipv6_unavail = errno == EAFNOSUPPORT;
                     /* If IPv6 socket and nsap is IPv4, make it
                        IPv4-mapped */
                     else if (nsap->sin6_family == AF_INET)
                         convaddr4to6(nsap);
              }
              if (EXT(statp).nssocks[ns] < 0)
                     EXT(statp).nssocks[ns] = socket(PF_INET, SOCK_DGRAM, 0);
              if (EXT(statp).nssocks[ns] < 0) {
                     *terrno = errno;
                     Perror(statp, stderr, "socket(dg)", 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.
               */
              if (connect(EXT(statp).nssocks[ns], (struct sockaddr *)nsap,
                         sizeof *nsap) < 0) {
                     Aerror(statp, stderr, "connect(dg)", errno,
                            (struct sockaddr *) nsap);
                     __res_iclose(statp, false);
                     return (0);
              }
              /* Make socket non-blocking.  */
              int fl = __fcntl (EXT(statp).nssocks[ns], F_GETFL);
              if  (fl != -1)
                     __fcntl (EXT(statp).nssocks[ns], F_SETFL,
                             fl | O_NONBLOCK);
              Dprint(statp->options & RES_DEBUG,
                     (stdout, ";; new DG socket\n"))
       }

       /*
        * Compute time for the total operation.
        */
       seconds = (statp->retrans << ns);
       if (ns > 0)
              seconds /= statp->nscount;
       if (seconds <= 0)
              seconds = 1;
       evNowTime(&now);
       evConsTime(&timeout, seconds, 0);
       evAddTime(&finish, &now, &timeout);
       int need_recompute = 0;
       int nwritten = 0;
       int recvresp1 = 0;
       int recvresp2 = buf2 == NULL;
       pfd[0].fd = EXT(statp).nssocks[ns];
       pfd[0].events = POLLOUT;
       if (resplen2 != NULL)
         *resplen2 = 0;
 wait:
       if (need_recompute) {
       recompute_resend:
              evNowTime(&now);
              if (evCmpTime(finish, now) <= 0) {
              poll_err_out:
                     Perror(statp, stderr, "poll", errno);
              err_out:
                     __res_iclose(statp, false);
                     return (0);
              }
              evSubTime(&timeout, &finish, &now);
       }
        /* 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 (__builtin_expect (n == 0, 0)) {
              n = __poll (pfd, 1, ptimeout);
              need_recompute = 1;
       }
       if (n == 0) {
              Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
              if (resplen > 1 && (recvresp1 || (buf2 != NULL && recvresp2)))
                {
                  *resplen2 = 1;
                  return resplen;
                }

              *gotsomewhere = 1;
              return (0);
       }
       if (n < 0) {
              if (errno == EINTR)
                     goto recompute_resend;

              goto poll_err_out;
       }
       __set_errno (0);
       if (pfd[0].revents & POLLOUT) {
              ssize_t sr;
              if (nwritten != 0)
                sr = send (pfd[0].fd, buf2, buflen2, MSG_NOSIGNAL);
              else
                sr = send (pfd[0].fd, buf, buflen, MSG_NOSIGNAL);

              if (sr != buflen) {
                     if (errno == EINTR || errno == EAGAIN)
                            goto recompute_resend;
                     Perror(statp, stderr, "send", errno);
                     goto err_out;
              }
              if (nwritten != 0 || buf2 == NULL)
                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) {
                     thisanssizp = anssizp;
                     thisansp = anscp ?: ansp;
                     assert (anscp != NULL || ansp2 == NULL);
                     thisresplenp = &resplen;
              } else {
                     if (*anssizp != MAXPACKET) {
                            /* No buffer allocated for the first
                               reply.  We can try to use the rest
                               of the user-provided buffer.  */
#ifdef _STRING_ARCH_unaligned
                            *anssizp2 = orig_anssizp - resplen;
                            *ansp2 = *ansp + resplen;
#else
                            int aligned_resplen
                              = ((resplen + __alignof__ (HEADER) - 1)
                                 & ~(__alignof__ (HEADER) - 1));
                            *anssizp2 = orig_anssizp - aligned_resplen;
                            *ansp2 = *ansp + aligned_resplen;
#endif
                     } else {
                            /* The first reply did not fit into the
                               user-provided buffer.  Maybe the second
                               answer will.  */
                            *anssizp2 = orig_anssizp;
                            *ansp2 = *ansp;
                     }

                     thisanssizp = anssizp2;
                     thisansp = ansp2;
                     thisresplenp = resplen2;
              }

              if (*thisanssizp < MAXPACKET
                  /* Yes, we test ANSCP here.  If we have two buffers
                     both will be allocatable.  */
                  && anscp
                  && (ioctl (pfd[0].fd, FIONREAD, thisresplenp) < 0
                     || *thisanssizp < *thisresplenp)) {
                     u_char *newp = malloc (MAXPACKET);
                     if (newp != NULL) {
                            *anssizp = MAXPACKET;
                            *thisansp = ans = newp;
                     }
              }
              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 (__builtin_expect (*thisresplenp <= 0, 0)) {
                     if (errno == EINTR || errno == EAGAIN) {
                            need_recompute = 1;
                            goto wait;
                     }
                     Perror(statp, stderr, "recvfrom", errno);
                     goto err_out;
              }
              *gotsomewhere = 1;
              if (__builtin_expect (*thisresplenp < HFIXEDSZ, 0)) {
                     /*
                      * Undersized message.
                      */
                     Dprint(statp->options & RES_DEBUG,
                            (stdout, ";; undersized: %d\n",
                            *thisresplen));
                     *terrno = EMSGSIZE;
                     goto err_out;
              }
              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.
                      */
                     DprintQ((statp->options & RES_DEBUG) ||
                            (statp->pfcode & RES_PRF_REPLY),
                            (stdout, ";; old answer:\n"),
                            thisansp,
                            (*thisresplen > *thisanssiz)
                            ? *thisanssiz : *thisresplen);
                     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.
                      */
                     DprintQ((statp->options & RES_DEBUG) ||
                            (statp->pfcode & RES_PRF_REPLY),
                            (stdout, ";; not our server:\n"),
                            thisansp,
                            (*thisresplen > *thisanssiz)
                            ? *thisanssiz : *thisresplen);
                     goto wait;
              }
#ifdef RES_USE_EDNS0
              if (anhp->rcode == FORMERR
                  && (statp->options & RES_USE_EDNS0) != 0U) {
                     /*
                      * Do not retry if the server does not understand
                      * EDNS0.  The case has to be captured here, as
                      * FORMERR packet do not carry query section, hence
                      * res_queriesmatch() returns 0.
                      */
                     DprintQ(statp->options & RES_DEBUG,
                            (stdout,
                             "server rejected query with EDNS0:\n"),
                            thisans,
                            (*thisresplen > *thisanssiz)
                            ? *thisanssiz : *thisresplen);
                     /* record the error */
                     statp->_flags |= RES_F_EDNS0ERR;
                     goto err_out;
        }
#endif
              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.
                      */
                     DprintQ((statp->options & RES_DEBUG) ||
                            (statp->pfcode & RES_PRF_REPLY),
                            (stdout, ";; wrong query name:\n"),
                            thisansp,
                            (*thisresplen > *thisanssiz)
                            ? *thisanssiz : *thisresplen);
                     goto wait;
              }
              if (anhp->rcode == SERVFAIL ||
                  anhp->rcode == NOTIMP ||
                  anhp->rcode == REFUSED) {
                     DprintQ(statp->options & RES_DEBUG,
                            (stdout, "server rejected query:\n"),
                            thisansp,
                            (*thisresplen > *thisanssiz)
                            ? *thisanssiz : *thisresplen);

                     if (recvresp1 || (buf2 != NULL && recvresp2))
                       {
                         *resplen2 = 1;
                         return resplen;
                       }
                     if (buf2 != NULL)
                       {
                         /* We are waiting for a possible second reply.  */
                         resplen = 1;
                         if (hp->id == anhp->id)
                           recvresp1 = 1;
                         else
                           recvresp2 = 1;

                         goto wait;
                       }

              next_ns:
                     __res_iclose(statp, false);
                     /* don't retry if called from dig */
                     if (!statp->pfcode)
                            return (0);
              }
              if (anhp->rcode == NOERROR && anhp->ancount == 0
                  && anhp->aa == 0 && anhp->ra == 0 && anhp->arcount == 0) {
                     DprintQ(statp->options & RES_DEBUG,
                            (stdout, "referred query:\n"),
                            thisansp,
                            (*thisresplen > *thisanssiz)
                            ? *thisanssiz : *thisresplen);
                     goto next_ns;
              }
              if (!(statp->options & RES_IGNTC) && anhp->tc) {
                     /*
                      * To get the rest of answer,
                      * use TCP with same server.
                      */
                     Dprint(statp->options & RES_DEBUG,
                            (stdout, ";; truncated answer\n"));
                     *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...
                     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)
                     goto wait;
              /*
               * All is well, or the error is fatal.  Signal that the
               * next nameserver ought not be tried.
               */
              return (resplen);
       } else if (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
              /* Something went wrong.  We can stop trying.  */
              goto err_out;
       }
       else {
              /* poll should not have returned > 0 in this case.  */
              abort ();
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

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  
) [static]

Here is the caller graph for this function:

static int sock_eq ( struct sockaddr_in6 a1,
struct sockaddr_in6 a2 
) [static]

Definition at line 1311 of file res_send.c.

                                                          {
       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));
}

Here is the call graph for this function:

Here is the caller graph for this function: