dns.c
changeset 0 068428edee47
equal deleted inserted replaced
-1:000000000000 0:068428edee47
       
     1 #include <stdio.h>
       
     2 #include <netdb.h>
       
     3 #include <sys/types.h>
       
     4 #include <netinet/in.h>
       
     5 #include <arpa/nameser.h>
       
     6 #include <resolv.h>
       
     7 #include <errno.h>
       
     8 extern int res_query();
       
     9 extern int res_search();
       
    10 extern int errno;
       
    11 extern int h_errno;
       
    12 #include "ip.h"
       
    13 #include "ipalloc.h"
       
    14 #include "fmt.h"
       
    15 #include "alloc.h"
       
    16 #include "str.h"
       
    17 #include "stralloc.h"
       
    18 #include "dns.h"
       
    19 #include "case.h"
       
    20 
       
    21 static unsigned short getshort(c) unsigned char *c;
       
    22 { unsigned short u; u = c[0]; return (u << 8) + c[1]; }
       
    23 
       
    24 static union { HEADER hdr; unsigned char buf[PACKETSZ]; } response;
       
    25 static int responselen;
       
    26 static unsigned char *responseend;
       
    27 static unsigned char *responsepos;
       
    28 
       
    29 static int numanswers;
       
    30 static char name[MAXDNAME];
       
    31 static struct ip_address ip;
       
    32 unsigned short pref;
       
    33 
       
    34 static stralloc glue = {0};
       
    35 
       
    36 static int (*lookup)() = res_query;
       
    37 
       
    38 static int resolve(domain,type)
       
    39 stralloc *domain;
       
    40 int type;
       
    41 {
       
    42  int n;
       
    43  int i;
       
    44 
       
    45  errno = 0;
       
    46  if (!stralloc_copy(&glue,domain)) return DNS_MEM;
       
    47  if (!stralloc_0(&glue)) return DNS_MEM;
       
    48  responselen = lookup(glue.s,C_IN,type,response.buf,sizeof(response));
       
    49  if (responselen <= 0)
       
    50   {
       
    51    if (errno == ECONNREFUSED) return DNS_SOFT;
       
    52    if (h_errno == TRY_AGAIN) return DNS_SOFT;
       
    53    return DNS_HARD;
       
    54   }
       
    55  if (responselen >= sizeof(response))
       
    56    responselen = sizeof(response);
       
    57  responseend = response.buf + responselen;
       
    58  responsepos = response.buf + sizeof(HEADER);
       
    59  n = ntohs(response.hdr.qdcount);
       
    60  while (n-- > 0)
       
    61   {
       
    62    i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME);
       
    63    if (i < 0) return DNS_SOFT;
       
    64    responsepos += i;
       
    65    i = responseend - responsepos;
       
    66    if (i < QFIXEDSZ) return DNS_SOFT;
       
    67    responsepos += QFIXEDSZ;
       
    68   }
       
    69  numanswers = ntohs(response.hdr.ancount);
       
    70  return 0;
       
    71 }
       
    72 
       
    73 static int findname(wanttype)
       
    74 int wanttype;
       
    75 {
       
    76  unsigned short rrtype;
       
    77  unsigned short rrdlen;
       
    78  int i;
       
    79 
       
    80  if (numanswers <= 0) return 2;
       
    81  --numanswers;
       
    82  if (responsepos == responseend) return DNS_SOFT;
       
    83 
       
    84  i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME);
       
    85  if (i < 0) return DNS_SOFT;
       
    86  responsepos += i;
       
    87 
       
    88  i = responseend - responsepos;
       
    89  if (i < 4 + 3 * 2) return DNS_SOFT;
       
    90    
       
    91  rrtype = getshort(responsepos);
       
    92  rrdlen = getshort(responsepos + 8);
       
    93  responsepos += 10;
       
    94 
       
    95  if (rrtype == wanttype)
       
    96   {
       
    97    if (dn_expand(response.buf,responseend,responsepos,name,MAXDNAME) < 0)
       
    98      return DNS_SOFT;
       
    99    responsepos += rrdlen;
       
   100    return 1;
       
   101   }
       
   102    
       
   103  responsepos += rrdlen;
       
   104  return 0;
       
   105 }
       
   106 
       
   107 static int findip(wanttype)
       
   108 int wanttype;
       
   109 {
       
   110  unsigned short rrtype;
       
   111  unsigned short rrdlen;
       
   112  int i;
       
   113 
       
   114  if (numanswers <= 0) return 2;
       
   115  --numanswers;
       
   116  if (responsepos == responseend) return DNS_SOFT;
       
   117 
       
   118  i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME);
       
   119  if (i < 0) return DNS_SOFT;
       
   120  responsepos += i;
       
   121 
       
   122  i = responseend - responsepos;
       
   123  if (i < 4 + 3 * 2) return DNS_SOFT;
       
   124    
       
   125  rrtype = getshort(responsepos);
       
   126  rrdlen = getshort(responsepos + 8);
       
   127  responsepos += 10;
       
   128 
       
   129  if (rrtype == wanttype)
       
   130   {
       
   131    if (rrdlen < 4)
       
   132      return DNS_SOFT;
       
   133    ip.d[0] = responsepos[0];
       
   134    ip.d[1] = responsepos[1];
       
   135    ip.d[2] = responsepos[2];
       
   136    ip.d[3] = responsepos[3];
       
   137    responsepos += rrdlen;
       
   138    return 1;
       
   139   }
       
   140    
       
   141  responsepos += rrdlen;
       
   142  return 0;
       
   143 }
       
   144 
       
   145 static int findmx(wanttype)
       
   146 int wanttype;
       
   147 {
       
   148  unsigned short rrtype;
       
   149  unsigned short rrdlen;
       
   150  int i;
       
   151 
       
   152  if (numanswers <= 0) return 2;
       
   153  --numanswers;
       
   154  if (responsepos == responseend) return DNS_SOFT;
       
   155 
       
   156  i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME);
       
   157  if (i < 0) return DNS_SOFT;
       
   158  responsepos += i;
       
   159 
       
   160  i = responseend - responsepos;
       
   161  if (i < 4 + 3 * 2) return DNS_SOFT;
       
   162    
       
   163  rrtype = getshort(responsepos);
       
   164  rrdlen = getshort(responsepos + 8);
       
   165  responsepos += 10;
       
   166 
       
   167  if (rrtype == wanttype)
       
   168   {
       
   169    if (rrdlen < 3)
       
   170      return DNS_SOFT;
       
   171    pref = (responsepos[0] << 8) + responsepos[1];
       
   172    if (dn_expand(response.buf,responseend,responsepos + 2,name,MAXDNAME) < 0)
       
   173      return DNS_SOFT;
       
   174    responsepos += rrdlen;
       
   175    return 1;
       
   176   }
       
   177    
       
   178  responsepos += rrdlen;
       
   179  return 0;
       
   180 }
       
   181 
       
   182 void dns_init(flagsearch)
       
   183 int flagsearch;
       
   184 {
       
   185  res_init();
       
   186  if (flagsearch) lookup = res_search;
       
   187 }
       
   188 
       
   189 int dns_cname(sa)
       
   190 stralloc *sa;
       
   191 {
       
   192  int r;
       
   193  int loop;
       
   194  for (loop = 0;loop < 10;++loop)
       
   195   {
       
   196    if (!sa->len) return loop;
       
   197    if (sa->s[sa->len - 1] == ']') return loop;
       
   198    if (sa->s[sa->len - 1] == '.') { --sa->len; continue; }
       
   199    switch(resolve(sa,T_ANY))
       
   200     {
       
   201      case DNS_MEM: return DNS_MEM;
       
   202      case DNS_SOFT: return DNS_SOFT;
       
   203      case DNS_HARD: return loop;
       
   204      default:
       
   205        while ((r = findname(T_CNAME)) != 2)
       
   206 	{
       
   207 	 if (r == DNS_SOFT) return DNS_SOFT;
       
   208 	 if (r == 1)
       
   209 	  {
       
   210 	   if (!stralloc_copys(sa,name)) return DNS_MEM;
       
   211 	   break;
       
   212 	  }
       
   213 	}
       
   214        if (r == 2) return loop;
       
   215     }
       
   216   }
       
   217  return DNS_HARD; /* alias loop */
       
   218 }
       
   219 
       
   220 #define FMT_IAA 40
       
   221 
       
   222 static int iaafmt(s,ip)
       
   223 char *s;
       
   224 struct ip_address *ip;
       
   225 {
       
   226  unsigned int i;
       
   227  unsigned int len;
       
   228  len = 0;
       
   229  i = fmt_ulong(s,(unsigned long) ip->d[3]); len += i; if (s) s += i;
       
   230  i = fmt_str(s,"."); len += i; if (s) s += i;
       
   231  i = fmt_ulong(s,(unsigned long) ip->d[2]); len += i; if (s) s += i;
       
   232  i = fmt_str(s,"."); len += i; if (s) s += i;
       
   233  i = fmt_ulong(s,(unsigned long) ip->d[1]); len += i; if (s) s += i;
       
   234  i = fmt_str(s,"."); len += i; if (s) s += i;
       
   235  i = fmt_ulong(s,(unsigned long) ip->d[0]); len += i; if (s) s += i;
       
   236  i = fmt_str(s,".in-addr.arpa."); len += i; if (s) s += i;
       
   237  return len;
       
   238 }
       
   239 
       
   240 int dns_ptr(sa,ip)
       
   241 stralloc *sa;
       
   242 struct ip_address *ip;
       
   243 {
       
   244  int r;
       
   245 
       
   246  if (!stralloc_ready(sa,iaafmt((char *) 0,ip))) return DNS_MEM;
       
   247  sa->len = iaafmt(sa->s,ip);
       
   248  switch(resolve(sa,T_PTR))
       
   249   {
       
   250    case DNS_MEM: return DNS_MEM;
       
   251    case DNS_SOFT: return DNS_SOFT;
       
   252    case DNS_HARD: return DNS_HARD;
       
   253   }
       
   254  while ((r = findname(T_PTR)) != 2)
       
   255   {
       
   256    if (r == DNS_SOFT) return DNS_SOFT;
       
   257    if (r == 1)
       
   258     {
       
   259      if (!stralloc_copys(sa,name)) return DNS_MEM;
       
   260      return 0;
       
   261     }
       
   262   }
       
   263  return DNS_HARD;
       
   264 }
       
   265 
       
   266 static int dns_ipplus(ia,sa,pref)
       
   267 ipalloc *ia;
       
   268 stralloc *sa;
       
   269 int pref;
       
   270 {
       
   271  int r;
       
   272  struct ip_mx ix;
       
   273 
       
   274  if (!stralloc_copy(&glue,sa)) return DNS_MEM;
       
   275  if (!stralloc_0(&glue)) return DNS_MEM;
       
   276  if (glue.s[0]) {
       
   277    ix.pref = 0;
       
   278    if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)])
       
   279     {
       
   280      if (!ipalloc_append(ia,&ix)) return DNS_MEM;
       
   281      return 0;
       
   282     }
       
   283  }
       
   284 
       
   285  switch(resolve(sa,T_A))
       
   286   {
       
   287    case DNS_MEM: return DNS_MEM;
       
   288    case DNS_SOFT: return DNS_SOFT;
       
   289    case DNS_HARD: return DNS_HARD;
       
   290   }
       
   291  while ((r = findip(T_A)) != 2)
       
   292   {
       
   293    ix.ip = ip;
       
   294    ix.pref = pref;
       
   295    if (r == DNS_SOFT) return DNS_SOFT;
       
   296    if (r == 1)
       
   297      if (!ipalloc_append(ia,&ix)) return DNS_MEM;
       
   298   }
       
   299  return 0;
       
   300 }
       
   301 
       
   302 int dns_ip(ia,sa)
       
   303 ipalloc *ia;
       
   304 stralloc *sa;
       
   305 {
       
   306  if (!ipalloc_readyplus(ia,0)) return DNS_MEM;
       
   307  ia->len = 0;
       
   308  return dns_ipplus(ia,sa,0);
       
   309 }
       
   310 
       
   311 int dns_mxip(ia,sa,random)
       
   312 ipalloc *ia;
       
   313 stralloc *sa;
       
   314 unsigned long random;
       
   315 {
       
   316  int r;
       
   317  struct mx { stralloc sa; unsigned short p; } *mx;
       
   318  struct ip_mx ix;
       
   319  int nummx;
       
   320  int i;
       
   321  int j;
       
   322  int flagsoft;
       
   323 
       
   324  if (!ipalloc_readyplus(ia,0)) return DNS_MEM;
       
   325  ia->len = 0;
       
   326 
       
   327  if (!stralloc_copy(&glue,sa)) return DNS_MEM;
       
   328  if (!stralloc_0(&glue)) return DNS_MEM;
       
   329  if (glue.s[0]) {
       
   330    ix.pref = 0;
       
   331    if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)])
       
   332     {
       
   333      if (!ipalloc_append(ia,&ix)) return DNS_MEM;
       
   334      return 0;
       
   335     }
       
   336  }
       
   337 
       
   338  switch(resolve(sa,T_MX))
       
   339   {
       
   340    case DNS_MEM: return DNS_MEM;
       
   341    case DNS_SOFT: return DNS_SOFT;
       
   342    case DNS_HARD: return dns_ip(ia,sa);
       
   343   }
       
   344 
       
   345  mx = (struct mx *) alloc(numanswers * sizeof(struct mx));
       
   346  if (!mx) return DNS_MEM;
       
   347  nummx = 0;
       
   348 
       
   349  while ((r = findmx(T_MX)) != 2)
       
   350   {
       
   351    if (r == DNS_SOFT) { alloc_free(mx); return DNS_SOFT; }
       
   352    if (r == 1)
       
   353     {
       
   354      mx[nummx].p = pref;
       
   355      mx[nummx].sa.s = 0;
       
   356      if (!stralloc_copys(&mx[nummx].sa,name))
       
   357       {
       
   358        while (nummx > 0) alloc_free(mx[--nummx].sa.s);
       
   359        alloc_free(mx); return DNS_MEM;
       
   360       }
       
   361      ++nummx;
       
   362     }
       
   363   }
       
   364 
       
   365  if (!nummx) return dns_ip(ia,sa); /* e.g., CNAME -> A */
       
   366 
       
   367  flagsoft = 0;
       
   368  while (nummx > 0)
       
   369   {
       
   370    unsigned long numsame;
       
   371 
       
   372    i = 0;
       
   373    numsame = 1;
       
   374    for (j = 1;j < nummx;++j)
       
   375      if (mx[j].p < mx[i].p)
       
   376       {
       
   377        i = j;
       
   378        numsame = 1;
       
   379       }
       
   380      else if (mx[j].p == mx[i].p)
       
   381       {
       
   382        ++numsame;
       
   383        random = random * 69069 + 1;
       
   384        if ((random / 2) < (2147483647 / numsame))
       
   385          i = j;
       
   386       }
       
   387 
       
   388    switch(dns_ipplus(ia,&mx[i].sa,mx[i].p))
       
   389     {
       
   390      case DNS_MEM: case DNS_SOFT:
       
   391        flagsoft = 1; break;
       
   392     }
       
   393 
       
   394    alloc_free(mx[i].sa.s);
       
   395    mx[i] = mx[--nummx];
       
   396   }
       
   397 
       
   398  alloc_free(mx);
       
   399  return flagsoft;
       
   400 }