4 #include <netinet/in.h>
5 #include <arpa/nameser.h>
8 extern int res_query();
9 extern int res_search();
21 static unsigned short getshort(c
) unsigned char *c
;
22 { unsigned short u
; u
= c
[0]; return (u
<< 8) + c
[1]; }
24 static union { HEADER hdr
; unsigned char buf
[PACKETSZ
]; } response
;
25 static int responselen
;
26 static unsigned char *responseend
;
27 static unsigned char *responsepos
;
29 static int numanswers
;
30 static char name
[MAXDNAME
];
31 static struct ip_address ip
;
34 static stralloc glue
= {0};
36 static int (*lookup
)() = res_query
;
38 static int resolve(domain
,type
)
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
));
51 if (errno
== ECONNREFUSED
) return DNS_SOFT
;
52 if (h_errno
== TRY_AGAIN
) return DNS_SOFT
;
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
);
62 i
= dn_expand(response
.buf
,responseend
,responsepos
,name
,MAXDNAME
);
63 if (i
< 0) return DNS_SOFT
;
65 i
= responseend
- responsepos
;
66 if (i
< QFIXEDSZ
) return DNS_SOFT
;
67 responsepos
+= QFIXEDSZ
;
69 numanswers
= ntohs(response
.hdr
.ancount
);
73 static int findname(wanttype
)
76 unsigned short rrtype
;
77 unsigned short rrdlen
;
80 if (numanswers
<= 0) return 2;
82 if (responsepos
== responseend
) return DNS_SOFT
;
84 i
= dn_expand(response
.buf
,responseend
,responsepos
,name
,MAXDNAME
);
85 if (i
< 0) return DNS_SOFT
;
88 i
= responseend
- responsepos
;
89 if (i
< 4 + 3 * 2) return DNS_SOFT
;
91 rrtype
= getshort(responsepos
);
92 rrdlen
= getshort(responsepos
+ 8);
95 if (rrtype
== wanttype
)
97 if (dn_expand(response
.buf
,responseend
,responsepos
,name
,MAXDNAME
) < 0)
99 responsepos
+= rrdlen
;
103 responsepos
+= rrdlen
;
107 static int findip(wanttype
)
110 unsigned short rrtype
;
111 unsigned short rrdlen
;
114 if (numanswers
<= 0) return 2;
116 if (responsepos
== responseend
) return DNS_SOFT
;
118 i
= dn_expand(response
.buf
,responseend
,responsepos
,name
,MAXDNAME
);
119 if (i
< 0) return DNS_SOFT
;
122 i
= responseend
- responsepos
;
123 if (i
< 4 + 3 * 2) return DNS_SOFT
;
125 rrtype
= getshort(responsepos
);
126 rrdlen
= getshort(responsepos
+ 8);
129 if (rrtype
== wanttype
)
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
;
141 responsepos
+= rrdlen
;
145 static int findmx(wanttype
)
148 unsigned short rrtype
;
149 unsigned short rrdlen
;
152 if (numanswers
<= 0) return 2;
154 if (responsepos
== responseend
) return DNS_SOFT
;
156 i
= dn_expand(response
.buf
,responseend
,responsepos
,name
,MAXDNAME
);
157 if (i
< 0) return DNS_SOFT
;
160 i
= responseend
- responsepos
;
161 if (i
< 4 + 3 * 2) return DNS_SOFT
;
163 rrtype
= getshort(responsepos
);
164 rrdlen
= getshort(responsepos
+ 8);
167 if (rrtype
== wanttype
)
171 pref
= (responsepos
[0] << 8) + responsepos
[1];
172 if (dn_expand(response
.buf
,responseend
,responsepos
+ 2,name
,MAXDNAME
) < 0)
174 responsepos
+= rrdlen
;
178 responsepos
+= rrdlen
;
182 void dns_init(flagsearch
)
186 if (flagsearch
) lookup
= res_search
;
194 for (loop
= 0;loop
< 10;++loop
)
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
))
201 case DNS_MEM
: return DNS_MEM
;
202 case DNS_SOFT
: return DNS_SOFT
;
203 case DNS_HARD
: return loop
;
205 while ((r
= findname(T_CNAME
)) != 2)
207 if (r
== DNS_SOFT
) return DNS_SOFT
;
210 if (!stralloc_copys(sa
,name
)) return DNS_MEM
;
214 if (r
== 2) return loop
;
217 return DNS_HARD
; /* alias loop */
222 static int iaafmt(s
,ip
)
224 struct ip_address
*ip
;
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
;
242 struct ip_address
*ip
;
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
))
250 case DNS_MEM
: return DNS_MEM
;
251 case DNS_SOFT
: return DNS_SOFT
;
252 case DNS_HARD
: return DNS_HARD
;
254 while ((r
= findname(T_PTR
)) != 2)
256 if (r
== DNS_SOFT
) return DNS_SOFT
;
259 if (!stralloc_copys(sa
,name
)) return DNS_MEM
;
266 static int dns_ipplus(ia
,sa
,pref
)
274 if (!stralloc_copy(&glue
,sa
)) return DNS_MEM
;
275 if (!stralloc_0(&glue
)) return DNS_MEM
;
278 if (!glue
.s
[ip_scan(glue
.s
,&ix
.ip
)] || !glue
.s
[ip_scanbracket(glue
.s
,&ix
.ip
)])
280 if (!ipalloc_append(ia
,&ix
)) return DNS_MEM
;
285 switch(resolve(sa
,T_A
))
287 case DNS_MEM
: return DNS_MEM
;
288 case DNS_SOFT
: return DNS_SOFT
;
289 case DNS_HARD
: return DNS_HARD
;
291 while ((r
= findip(T_A
)) != 2)
295 if (r
== DNS_SOFT
) return DNS_SOFT
;
297 if (!ipalloc_append(ia
,&ix
)) return DNS_MEM
;
306 if (!ipalloc_readyplus(ia
,0)) return DNS_MEM
;
308 return dns_ipplus(ia
,sa
,0);
311 int dns_mxip(ia
,sa
,random
)
314 unsigned long random
;
317 struct mx
{ stralloc sa
; unsigned short p
; } *mx
;
324 if (!ipalloc_readyplus(ia
,0)) return DNS_MEM
;
327 if (!stralloc_copy(&glue
,sa
)) return DNS_MEM
;
328 if (!stralloc_0(&glue
)) return DNS_MEM
;
331 if (!glue
.s
[ip_scan(glue
.s
,&ix
.ip
)] || !glue
.s
[ip_scanbracket(glue
.s
,&ix
.ip
)])
333 if (!ipalloc_append(ia
,&ix
)) return DNS_MEM
;
338 switch(resolve(sa
,T_MX
))
340 case DNS_MEM
: return DNS_MEM
;
341 case DNS_SOFT
: return DNS_SOFT
;
342 case DNS_HARD
: return dns_ip(ia
,sa
);
345 mx
= (struct mx
*) alloc(numanswers
* sizeof(struct mx
));
346 if (!mx
) return DNS_MEM
;
349 while ((r
= findmx(T_MX
)) != 2)
351 if (r
== DNS_SOFT
) { alloc_free(mx
); return DNS_SOFT
; }
356 if (!stralloc_copys(&mx
[nummx
].sa
,name
))
358 while (nummx
> 0) alloc_free(mx
[--nummx
].sa
.s
);
359 alloc_free(mx
); return DNS_MEM
;
365 if (!nummx
) return dns_ip(ia
,sa
); /* e.g., CNAME -> A */
370 unsigned long numsame
;
374 for (j
= 1;j
< nummx
;++j
)
375 if (mx
[j
].p
< mx
[i
].p
)
380 else if (mx
[j
].p
== mx
[i
].p
)
383 random
= random
* 69069 + 1;
384 if ((random
/ 2) < (2147483647 / numsame
))
388 switch(dns_ipplus(ia
,&mx
[i
].sa
,mx
[i
].p
))
390 case DNS_MEM
: case DNS_SOFT
:
394 alloc_free(mx
[i
].sa
.s
);