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