Back to index

courier  0.68.2
rfc1035.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 1998 - 2011 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      <stdlib.h>
00010 #include      <string.h>
00011 #include      <errno.h>
00012 #include      <sys/types.h>
00013 #if TIME_WITH_SYS_TIME
00014 #include      <sys/time.h>
00015 #include      <time.h>
00016 #else
00017 #if HAVE_SYS_TIME_H
00018 #include      <sys/time.h>
00019 #else
00020 #include      <time.h>
00021 #endif
00022 #endif
00023 #include      <arpa/inet.h>
00024 #if    HAVE_UNISTD_H
00025 #include      <unistd.h>
00026 #endif
00027 
00028 #include      "rfc1035.h"
00029 
00030 
00031 #define ISSPACE(c) (strchr(" \t\r\n", (int)(unsigned char)(c)) != NULL)
00032 
00033 #if RFC1035_IPV6
00034 
00035 #else
00036 
00037 struct in_addr       rfc1035_addr_any={INADDR_ANY};
00038 
00039 #endif
00040 
00041 void rfc1035_init_timeout(struct rfc1035_res *res, unsigned s, unsigned n)
00042 {
00043        res->rfc1035_timeout_initial=s;
00044        res->rfc1035_timeout_backoff=n;
00045 }
00046 
00047 void rfc1035_init_ns(struct rfc1035_res *res, const RFC1035_ADDR *a, unsigned n)
00048 {
00049 unsigned i;
00050 unsigned j;
00051 
00052        j=0;
00053 
00054        random128_binary(&res->randseed);
00055        md5_digest(&res->randseed, sizeof(res->randseed), res->randbuf);
00056        res->randptr=0;
00057 
00058        for (i=0; i == 0 || (i<n && i<RFC1035_MAXNS); i++)
00059        {
00060 #if RFC1035_IPV6
00061        struct in6_addr sin;
00062 
00063               if (n == 0)
00064                      sin=in6addr_loopback;
00065               else
00066                      sin=a[(j+i)%n];
00067 
00068 #else
00069        struct in_addr sin;
00070 
00071               if (n == 0)
00072               {
00073                      rfc1035_aton("127.0.0.1", &sin);
00074               }
00075               else
00076                      sin=a[(j+i)%n];
00077               memset(&res->nameservers[i], 0, sizeof(res->nameservers[i]));
00078               res->nameservers[i]=sin;
00079 #endif
00080               res->nameservers[i]=sin;
00081        }
00082        res->rfc1035_nnameservers=i;
00083 
00084 }
00085 
00086 int rfc1035_init_defaultdomain(struct rfc1035_res *res, const char *p)
00087 {
00088 char   *q;
00089 
00090        if (res->rfc1035_defaultdomain)
00091               free(res->rfc1035_defaultdomain);
00092 
00093        if ((res->rfc1035_defaultdomain=malloc(strlen(p)+1)) == 0)
00094               return (-1);
00095 
00096        strcpy(res->rfc1035_defaultdomain, p);
00097        for (q=res->rfc1035_defaultdomain; *q; q++)
00098               if (ISSPACE(*q))
00099               {
00100                      *q=0;
00101                      break;
00102               }
00103 
00104        return (0);
00105 }
00106 
00107 void rfc1035_init_dnssec_enable(struct rfc1035_res *res, int flag)
00108 {
00109        rfc1035_init_edns_payload(res, flag ? 1280:0);
00110 }
00111 
00112 
00113 void rfc1035_init_edns_payload(struct rfc1035_res *res, int payload_size)
00114 {
00115        res->dnssec_payload_size=payload_size;
00116 }
00117 
00118 static char tl(char c)
00119 {
00120        if (c >= 'A' && c <= 'Z')
00121               c += 'a' - 'A';
00122 
00123        return c;
00124 }
00125 
00126 void rfc1035_init_resolv(struct rfc1035_res *res)
00127 {
00128 FILE   *fp=fopen("/etc/resolv.conf", "r");
00129 char rfc1035_buf[512];
00130 RFC1035_ADDR ns[RFC1035_MAXNS];
00131 int nns=0;
00132 
00133        memset(res, 0, sizeof(*res));
00134 
00135        while (fp && fgets(rfc1035_buf, sizeof(rfc1035_buf), fp))
00136        {
00137        char   *p;
00138 
00139               for (p=rfc1035_buf; *p; p++)
00140                      *p=tl(*p);
00141 
00142               for (p=rfc1035_buf; *p; p++)
00143                      if (ISSPACE(*p))     break;
00144               if (*p)       *p++=0;
00145 
00146               if (strcmp(rfc1035_buf, "domain") == 0)
00147               {
00148                      while (p && ISSPACE(*p))
00149                             ++p;
00150                      rfc1035_init_defaultdomain(res, p);
00151                      continue;
00152               }
00153 
00154               if (strcmp(rfc1035_buf, "nameserver"))    continue;
00155               while (*p && ISSPACE(*p))   p++;
00156               if (nns < RFC1035_MAXNS)
00157               {
00158               char   *q;
00159 
00160                      for (q=p; *q && !ISSPACE(*q); q++)
00161                             ;
00162                      *q=0;
00163 
00164                      if (rfc1035_aton(p, &ns[nns++]) < 0)
00165                             --nns;
00166               }
00167        }
00168        if (fp) fclose(fp);
00169 
00170        rfc1035_init_ns(res, ns, nns);
00171 }
00172 
00173 void rfc1035_destroy_resolv(struct rfc1035_res *res)
00174 {
00175        if (res->rfc1035_defaultdomain)
00176        {
00177               free(res->rfc1035_defaultdomain);
00178        }
00179 }
00180 
00181 /************/
00182 
00183 struct compresslist {
00184        struct compresslist *next;
00185        unsigned offset;
00186        const char *ptr;
00187        } ;
00188 
00189 static int mkpacketq(void (*)(const char *, unsigned, void *), void *,
00190               unsigned *,
00191               const struct rfc1035_query *,
00192               unsigned,
00193               const char *,
00194               struct compresslist *,
00195               struct rfc1035_res *);
00196 
00197 unsigned rfc1035_next_randid(struct rfc1035_res *res)
00198 {
00199        unsigned i;
00200 
00201        if (res->randptr >= sizeof(res->randbuf))
00202        {
00203               for (i=0; i<sizeof(res->randseed); i++)
00204                      if ( ++((unsigned char *)res->randseed)[i])
00205                             break;
00206 
00207               md5_digest(res->randseed, sizeof(res->randseed),
00208                         res->randbuf);
00209               res->randptr=0;
00210        }
00211 
00212        i= ((unsigned)((unsigned char *)res->randbuf)[res->randptr] << 8) |
00213               ((unsigned char *)res->randbuf)[res->randptr+1];
00214        res->randptr += 2;
00215        return i;
00216 }
00217 
00218 int rfc1035_mkquery(struct rfc1035_res *res,     /* resolver */
00219                      unsigned opcode,     /* opcode */
00220                      const struct rfc1035_query *questions,
00221                      unsigned nquestions,
00222                      void (*func)(const char *, unsigned, void *), void *arg)
00223 {
00224 struct {
00225        unsigned char idhi, idlo;
00226        unsigned char infohi, infolo;
00227        unsigned char qhi, qlo;
00228        unsigned char ahi, alo;
00229        unsigned char nhi, nlo;
00230        unsigned char auhi, aulo;
00231        } header;
00232 unsigned cnt;
00233 
00234        unsigned id=rfc1035_next_randid(res);
00235 
00236        header.idhi= id >> 8;
00237        header.idlo= id;
00238 
00239        header.infohi= (opcode << 3) & 0x78;
00240 
00241        if (!res->norecursive)
00242               header.infohi |= 1; /* Want a recursive query */
00243        header.infolo=0;
00244        header.qhi=nquestions >> 8;
00245        header.qlo=nquestions;
00246        header.ahi=0;
00247        header.alo=0;
00248        header.nhi=0;
00249        header.nlo=0;
00250        header.auhi=0;
00251        header.aulo=0;
00252 
00253        if (res->dnssec_payload_size)
00254               header.aulo=1;
00255 
00256        (*func)( (const char *)&header, sizeof(header), arg);
00257        cnt=sizeof(header);
00258        if (nquestions)
00259               if (mkpacketq(func, arg, &cnt, questions, nquestions,
00260                      questions->name, 0, res))   return (-1);
00261 
00262        if (res->dnssec_payload_size)
00263        {
00264               /* RFC 2671, section 4.3 */
00265 
00266               struct {
00267                      char opt_root_domain_name;
00268                      char opt_type_hi;
00269                      char opt_type_lo;
00270                      char opt_class_hi;
00271                      char opt_class_lo;
00272                      char opt_extendedrcode;
00273                      char opt_version;
00274                      char opt_ttl_zhi;
00275                      char opt_ttl_zlo;
00276                      char opt_rdlen_hi;
00277                      char opt_rdlen_lo;
00278               } rfc2671_43;
00279 
00280               memset(&rfc2671_43, 0, sizeof(rfc2671_43));
00281 
00282               rfc2671_43.opt_type_lo=RFC1035_TYPE_OPT;
00283 
00284               rfc2671_43.opt_class_hi= res->dnssec_payload_size >> 8;
00285               rfc2671_43.opt_class_lo= res->dnssec_payload_size;
00286               rfc2671_43.opt_ttl_zhi |= 0x80; /* RFC 3225 */
00287 
00288               (*func)((char *)&rfc2671_43, sizeof(rfc2671_43), arg);
00289        }
00290 
00291        return (0);
00292 }
00293 
00294 int rfc1035_hostnamecmp(const char *p, const char *q)
00295 {
00296        while (*p || *q)
00297        {
00298               if (*p == '.' || *q == '.' )
00299               {
00300                      if ( (*p && *p != '.') || (*q && *q != '.'))
00301                             return (1);
00302                      while (*p == '.')    ++p;
00303                      while (*q == '.')    ++q;
00304                      continue;
00305               }
00306               if (!*p || !*q)      return (1);
00307               if ( tl(*p) != tl(*q))      return (1);
00308               ++p;
00309               ++q;
00310        }
00311        return (0);
00312 }
00313 
00314 static struct compresslist *search(struct compresslist *cp, const char *name)
00315 {
00316        for ( ; cp; cp=cp->next)
00317        {
00318               if (rfc1035_hostnamecmp(name, cp->ptr) == 0 &&
00319                      (cp->offset & 0x3FFF) == cp->offset)
00320                      return (cp);
00321                      /* Packet compression uses the two high bits */
00322        }
00323        return (0);
00324 }
00325 
00326 static int mkpacketq_full(void (*)(const char *, unsigned, void *),
00327               void *,
00328               unsigned *,
00329               const struct rfc1035_query *,
00330               unsigned,
00331               const char *,
00332               struct compresslist *, struct rfc1035_res *);
00333 
00334 static int mkpacketq(void (*func)(const char *, unsigned, void *), void *arg,
00335               unsigned *cnt,
00336               const struct rfc1035_query *qp,
00337               unsigned nqp,
00338               const char *nameptr,
00339               struct compresslist *comp_list,
00340               struct rfc1035_res *res)
00341 {
00342 char   *buf;
00343 int    rc;
00344 
00345 
00346        if (!res->rfc1035_defaultdomain || strchr(nameptr, '.'))
00347               return (mkpacketq_full(func, arg, cnt, qp, nqp, nameptr,
00348                      comp_list, res));
00349 
00350        /* Append default domain */
00351 
00352        if ((buf=malloc(strlen(nameptr)+
00353               strlen(res->rfc1035_defaultdomain)+2)) == 0)
00354               return (-1);
00355 
00356        strcat(strcat(strcpy(buf, nameptr), "."),
00357               res->rfc1035_defaultdomain);
00358 
00359        rc=mkpacketq_full(func, arg, cnt, qp, nqp, buf, comp_list, res);
00360        free(buf);
00361        return (rc);
00362 }
00363 
00364 static int mkpacketq_full(void (*func)(const char *, unsigned, void *),
00365               void *arg,
00366               unsigned *cnt,
00367               const struct rfc1035_query *qp,
00368               unsigned nqp,
00369               const char *nameptr,
00370               struct compresslist *comp_list,
00371               struct rfc1035_res *res)
00372 {
00373 unsigned llen;
00374 struct compresslist *cp;
00375 
00376        while (nameptr && *nameptr == '.')
00377               ++nameptr;
00378 
00379        if (!nameptr || !*nameptr)
00380        {
00381        struct {
00382               unsigned char padtail;
00383               unsigned char qtypehi, qtypelo;
00384               unsigned char qclasshi, qclasslo;
00385               } qtail;
00386 
00387               qtail.padtail=0;
00388               qtail.qtypehi=qp->qtype >> 8;
00389               qtail.qtypelo=qp->qtype;
00390               qtail.qclasshi=qp->qclass >> 8;
00391               qtail.qclasslo=qp->qclass;
00392 
00393               (*func)((const char *)&qtail, sizeof(qtail), arg);
00394               ++qp;
00395               --nqp;
00396               *cnt += sizeof(qtail);
00397               if (nqp)
00398                      return (mkpacketq(func, arg, cnt,
00399                             qp, nqp, qp->name, comp_list, res));
00400               return (0);
00401        }
00402 
00403        for (llen=0; nameptr[llen] && nameptr[llen] != '.'; llen++)
00404               ;
00405        cp=search(comp_list, nameptr);
00406        if (cp)
00407        {
00408        struct {
00409               unsigned char ptrhi, ptrlo;
00410               unsigned char qtypehi, qtypelo;
00411               unsigned char qclasshi, qclasslo;
00412               } qtail;
00413 
00414               qtail.ptrhi= (cp->offset >> 8) | 0xC0;
00415               qtail.ptrlo= cp->offset;
00416               qtail.qtypehi=qp->qtype >> 8;
00417               qtail.qtypelo=qp->qtype;
00418               qtail.qclasshi=qp->qclass >> 8;
00419               qtail.qclasslo=qp->qclass;
00420 
00421               (*func)( (const char *)&qtail, sizeof(qtail), arg);
00422               ++qp;
00423               --nqp;
00424               *cnt += sizeof(qtail);
00425 
00426               if (nqp)
00427                      return (mkpacketq(func, arg, cnt,
00428                             qp, nqp, qp->name, comp_list, res));
00429        }
00430        else
00431        {
00432        unsigned n=llen;
00433        unsigned char c;
00434        struct compresslist newc;
00435 
00436               if (n > 63)   return (-1);
00437 
00438               newc.next=comp_list;
00439               newc.offset= *cnt;
00440               newc.ptr=nameptr;
00441 
00442               c=(unsigned char)n;
00443               (*func)((const char *) &c, 1, arg);
00444               (*func)( nameptr, c, arg);
00445               *cnt += 1+c;
00446               return (mkpacketq_full(func, arg, cnt,
00447                             qp, nqp, nameptr+llen, &newc, res));
00448        }
00449        return (0);
00450 }
00451 
00452 /*******************************************************/
00453 
00454 int rfc1035_wait_reply(int fd, unsigned nsecs)
00455 {
00456 fd_set fds;
00457 struct timeval tv;
00458 int    n;
00459 
00460        FD_ZERO(&fds);
00461        FD_SET(fd, &fds);
00462        tv.tv_sec=nsecs;
00463        tv.tv_usec=0;
00464        while ((n=sox_select(fd+1, &fds, 0, 0, &tv)) < 0)
00465        {
00466               if (errno != EINTR)
00467                      break;
00468        }
00469 
00470        if (n > 0 && FD_ISSET(fd, &fds))
00471               return (0);
00472        errno=ETIMEDOUT;
00473        return (-1);
00474 }
00475 
00476 int rfc1035_wait_query(int fd, unsigned nsecs)
00477 {
00478 fd_set fds;
00479 struct timeval tv;
00480 int    n;
00481 
00482        FD_ZERO(&fds);
00483        FD_SET(fd, &fds);
00484        tv.tv_sec=nsecs;
00485        tv.tv_usec=0;
00486        while ((n=sox_select(fd+1, 0, &fds, 0, &tv)) < 0)
00487        {
00488               if (errno != EINTR)
00489                      break;
00490        }
00491 
00492        if (n > 0 && FD_ISSET(fd, &fds))
00493               return (0);
00494        errno=ETIMEDOUT;
00495        return (-1);
00496 }