Back to index

courier  0.68.2
rfc1035resolve.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 1998 - 2000 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 
00006 #include      "config.h"
00007 #include      <stdio.h>
00008 #include      "soxwrap/soxwrap.h"
00009 #include      "rfc1035.h"
00010 #include      <errno.h>
00011 #if    HAVE_UNISTD_H
00012 #include      <unistd.h>
00013 #endif
00014 #include      <stdlib.h>
00015 #include      <string.h>
00016 
00017 
00018 struct querybuf {
00019        char qbuf[512];
00020        unsigned qbuflen;
00021        } ;
00022 
00023 static void putqbuf(const char *p, unsigned l, void *q)
00024 {
00025 struct querybuf *qp=(struct querybuf *)q;
00026 
00027        if (qp->qbuflen < sizeof(qp->qbuf) &&
00028                      sizeof(qp->qbuf) - qp->qbuflen >= l)
00029               memcpy(qp->qbuf+qp->qbuflen, p, l);
00030        qp->qbuflen += l;
00031 }
00032 
00033 struct rfc1035_reply *rfc1035_resolve_multiple(
00034                      struct rfc1035_res *res,
00035                      int opcode,
00036                      const struct rfc1035_query *queries,
00037                      unsigned nqueries)
00038 {
00039 struct querybuf qbuf;
00040 int    udpfd;
00041 int    attempt;
00042 const RFC1035_ADDR *ns;
00043 unsigned nscount;
00044 unsigned current_timeout, timeout_backoff;
00045 unsigned nbackoff, backoff_num;
00046 int    af;
00047 static const char fakereply[]={0, 0, 0, RFC1035_RCODE_SERVFAIL,
00048               0, 0,
00049               0, 0,
00050               0, 0,
00051               0, 0};
00052 
00053        nscount=res->rfc1035_nnameservers;
00054        ns=res->nameservers;
00055 
00056        if (res->rfc1035_good_ns >= nscount)
00057               res->rfc1035_good_ns=0;
00058 
00059        qbuf.qbuflen=0;
00060        if ( rfc1035_mkquery(res,
00061               opcode, queries, nqueries, &putqbuf, &qbuf))
00062        {
00063               errno=EINVAL;
00064               return (0);
00065        }
00066 
00067        /* Prepare the UDP socket */
00068 
00069        if ((udpfd=rfc1035_open_udp(&af)) < 0)    return (0);
00070 
00071        /* Keep trying until we get an answer from a nameserver */
00072 
00073        current_timeout=res->rfc1035_timeout_initial;
00074        nbackoff=res->rfc1035_timeout_backoff;
00075        if (!current_timeout)       current_timeout=RFC1035_DEFAULT_INITIAL_TIMEOUT;
00076        if (!nbackoff)       nbackoff=RFC1035_DEFAULT_MAXIMUM_BACKOFF;
00077 
00078        timeout_backoff=current_timeout;
00079     for (backoff_num=0; backoff_num < nbackoff; backoff_num++,
00080                                    current_timeout *= timeout_backoff)
00081 
00082 
00083        for ( attempt=0; attempt < nscount; ++attempt)
00084        {
00085        int    nbytes;
00086        char   *reply;
00087        struct rfc1035_reply *rfcreply=0;
00088 
00089        const RFC1035_ADDR *sin=&ns[(res->rfc1035_good_ns+attempt) % nscount];
00090        int    sin_len=sizeof(*sin);
00091 
00092        int    dotcp=0, isaxfr=0;
00093        unsigned i;
00094 
00095               for (i=0; i<nqueries; i++)
00096                      if (queries[i].qtype == RFC1035_TYPE_AXFR)
00097                      {
00098                             dotcp=1;
00099                             isaxfr=1;
00100                             break;
00101                      }
00102 
00103               if (isaxfr && nqueries > 1)
00104                      return (rfc1035_replyparse(fakereply,
00105                             sizeof(fakereply)));
00106 
00107               if (!dotcp)
00108               {
00109               /* Send the query via UDP */
00110               RFC1035_NETADDR      addrbuf;
00111               const struct sockaddr *addrptr;
00112               int    addrptrlen;
00113 
00114                      if (rfc1035_mkaddress(af, &addrbuf,
00115                             sin, htons(53),
00116                             &addrptr, &addrptrlen))
00117                             continue;
00118 
00119                      if ((reply=rfc1035_query_udp(res, udpfd, addrptr,
00120                             addrptrlen, qbuf.qbuf, qbuf.qbuflen, &nbytes,
00121                                    current_timeout)) == 0)
00122                             continue;
00123 
00124                      res->rfc1035_good_ns= (res->rfc1035_good_ns + attempt) %
00125                                    nscount;
00126 
00127               /* Parse the reply */
00128 
00129                      rfcreply=rfc1035_replyparse(reply, nbytes);
00130                      if (!rfcreply)
00131                      {
00132                             free(reply);
00133                             if (errno == ENOMEM) break;
00134                             continue;
00135                      /* Bad response from the server, try the next one. */
00136                      }
00137                      rfcreply->mallocedbuf=reply;
00138               /*
00139               ** If the reply came back with the truncated bit set,
00140               ** retry the query via TCP.
00141               */
00142 
00143                      if (rfcreply->tc)
00144                      {
00145                             dotcp=1;
00146                             rfc1035_replyfree(rfcreply);
00147                      }
00148               }
00149 
00150               if (dotcp)
00151               {
00152               int    tcpfd;
00153               struct rfc1035_reply *firstreply=0, *lastreply=0;
00154 
00155                      if ((tcpfd=rfc1035_open_tcp(res, sin)) < 0)
00156                             continue;     /*
00157                                           ** Can't connect via TCP,
00158                                           ** try the next server.
00159                                           */
00160 
00161                      reply=rfc1035_query_tcp(res, tcpfd, qbuf.qbuf,
00162                             qbuf.qbuflen, &nbytes, current_timeout);
00163 
00164                      if (!reply)
00165                      {
00166                             sox_close(tcpfd);
00167                             continue;
00168                      }
00169 
00170                      res->rfc1035_good_ns= (res->rfc1035_good_ns
00171                                    + attempt) % nscount;
00172 
00173                      rfcreply=rfc1035_replyparse(reply, nbytes);
00174                      if (!rfcreply)
00175                      {
00176                             free(reply);
00177                             sox_close(tcpfd);
00178                             continue;
00179                      }
00180                      rfcreply->mallocedbuf=reply;
00181                      firstreply=lastreply=rfcreply;
00182                      while (isaxfr && rfcreply->rcode == 0)
00183                      {
00184                             if ((reply=rfc1035_recv_tcp(res,
00185                                    tcpfd, &nbytes, current_timeout))==0)
00186                                    break;
00187                             
00188                             rfcreply=rfc1035_replyparse(reply, nbytes);
00189                             if (!rfcreply)
00190                             {
00191                                    free(reply);
00192                                    rfc1035_replyfree(firstreply);
00193                                    firstreply=0;
00194                                    break;
00195                             }
00196                             rfcreply->mallocedbuf=reply;
00197                             lastreply->next=rfcreply;
00198                             lastreply=rfcreply;
00199 
00200                             if ( rfcreply->ancount &&
00201                                    rfcreply->anptr[0].rrtype ==
00202                                           RFC1035_TYPE_SOA)
00203                                    break;
00204                      }
00205                      sox_close(tcpfd);
00206                      if (!firstreply)
00207                             return (0);
00208                      rfcreply=firstreply;
00209               }
00210               memcpy(&rfcreply->server_addr, sin, sin_len);
00211               sox_close(udpfd);
00212               return (rfcreply);
00213        }
00214 
00215        /*
00216        ** Return a fake server failure reply, when we couldn't contact
00217        ** any name server.
00218        */
00219        sox_close(udpfd);
00220        return (rfc1035_replyparse(fakereply, sizeof(fakereply)));
00221 }
00222 
00223 struct rfc1035_reply *rfc1035_resolve(
00224        struct rfc1035_res *res,
00225        int opcode,
00226        const char *name,
00227        unsigned qtype,
00228        unsigned qclass)
00229 {
00230 struct rfc1035_query q;
00231 
00232        q.name=name;
00233        q.qtype=qtype;
00234        q.qclass=qclass;
00235        return (rfc1035_resolve_multiple(res, opcode, &q, 1));
00236 }