rev |
line source |
meillo@0
|
1 /* MasqMail Copyright (C) Oliver Kurth,
|
meillo@0
|
2 *
|
meillo@0
|
3 * This program is free software; you can redistribute it and/or modify
|
meillo@0
|
4 * it under the terms of the GNU General Public License as published by
|
meillo@0
|
5 * the Free Software Foundation; either version 2 of the License, or
|
meillo@0
|
6 * (at your option) any later version.
|
meillo@0
|
7 *
|
meillo@0
|
8 * This program is distributed in the hope that it will be useful,
|
meillo@0
|
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
meillo@0
|
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
meillo@0
|
11 * GNU General Public License for more details.
|
meillo@0
|
12 *
|
meillo@0
|
13 * You should have received a copy of the GNU General Public License
|
meillo@0
|
14 * along with this program; if not, write to the Free Software
|
meillo@0
|
15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
meillo@0
|
16 */
|
meillo@0
|
17
|
meillo@0
|
18 #include <sys/types.h>
|
meillo@0
|
19 #include <netinet/in.h>
|
meillo@0
|
20 #include <arpa/nameser.h>
|
meillo@0
|
21 #include <resolv.h>
|
meillo@0
|
22
|
meillo@0
|
23 #include "masqmail.h"
|
meillo@0
|
24
|
meillo@0
|
25 #ifdef RESOLV_TEST
|
meillo@0
|
26
|
meillo@0
|
27 #undef DEBUG
|
meillo@0
|
28 #define DEBUG(x) if(x > 0)
|
meillo@0
|
29
|
meillo@0
|
30 #define debugf g_print
|
meillo@0
|
31 #endif
|
meillo@0
|
32
|
meillo@0
|
33 #ifdef ENABLE_RESOLVER
|
meillo@0
|
34
|
meillo@0
|
35 static union {
|
meillo@0
|
36 HEADER hdr;
|
meillo@0
|
37 unsigned char buf[PACKETSZ];
|
meillo@0
|
38 } response;
|
meillo@0
|
39 static unsigned char *resp_end;
|
meillo@0
|
40 static unsigned char *resp_pos;
|
meillo@0
|
41
|
meillo@0
|
42 static int num_answers;
|
meillo@0
|
43 static char name[MAX_DNSNAME];
|
meillo@0
|
44
|
meillo@0
|
45 unsigned short rr_type;
|
meillo@0
|
46 unsigned short rr_dlen;
|
meillo@0
|
47
|
meillo@0
|
48 static
|
meillo@0
|
49 unsigned short getshort(unsigned char *c)
|
meillo@0
|
50 {
|
meillo@0
|
51 unsigned short u;
|
meillo@0
|
52 u = c[0];
|
meillo@0
|
53 return (u << 8) + c[1];
|
meillo@0
|
54 }
|
meillo@0
|
55
|
meillo@0
|
56 static
|
meillo@0
|
57 int dns_resolve(char *domain, int type, gboolean do_search)
|
meillo@0
|
58 {
|
meillo@0
|
59 int n;
|
meillo@0
|
60 int i;
|
meillo@0
|
61
|
meillo@0
|
62 int resp_len;
|
meillo@0
|
63 /*errno = 0;*/
|
meillo@0
|
64
|
meillo@0
|
65 /*
|
meillo@0
|
66 if (!stralloc_copy(&glue,domain)) return DNS_MEM;
|
meillo@0
|
67 if (!stralloc_0(&glue)) return DNS_MEM;
|
meillo@0
|
68 */
|
meillo@0
|
69
|
meillo@0
|
70 // resp_len = res_query(domain, C_IN, type, response.buf, sizeof(response));
|
meillo@0
|
71 DEBUG(5) debugf("DNS: before res_search()\n");
|
meillo@0
|
72 if(do_search)
|
meillo@0
|
73 resp_len = res_search(domain, C_IN, type, response.buf, sizeof(response));
|
meillo@0
|
74 else
|
meillo@0
|
75 resp_len = res_query(domain, C_IN, type, response.buf, sizeof(response));
|
meillo@0
|
76 DEBUG(5) debugf("DBG: after res_search()\n");
|
meillo@0
|
77
|
meillo@0
|
78 if (resp_len <= 0){
|
meillo@0
|
79 /*
|
meillo@0
|
80 if (errno == ECONNREFUSED) return DNS_SOFT;
|
meillo@0
|
81 if (h_errno == TRY_AGAIN) return DNS_SOFT;
|
meillo@0
|
82 return DNS_HARD;
|
meillo@0
|
83 */
|
meillo@0
|
84 return -1;
|
meillo@0
|
85 }
|
meillo@0
|
86 if (resp_len >= sizeof(response))
|
meillo@0
|
87 resp_len = sizeof(response);
|
meillo@0
|
88
|
meillo@0
|
89 resp_end = response.buf + resp_len;
|
meillo@0
|
90 resp_pos = response.buf + sizeof(HEADER);
|
meillo@0
|
91 n = ntohs(response.hdr.qdcount);
|
meillo@0
|
92
|
meillo@0
|
93 while (n-- > 0){
|
meillo@0
|
94 i = dn_expand(response.buf, resp_end, resp_pos, name, MAX_DNSNAME);
|
meillo@0
|
95 if (i < 0)
|
meillo@0
|
96 return -1;
|
meillo@0
|
97 DEBUG(5) debugf("DBG: resolve name = %s\n", name);
|
meillo@0
|
98 resp_pos += i;
|
meillo@0
|
99 i = resp_end - resp_pos;
|
meillo@0
|
100 if (i < QFIXEDSZ)
|
meillo@0
|
101 return -1;
|
meillo@0
|
102 resp_pos += QFIXEDSZ;
|
meillo@0
|
103 }
|
meillo@0
|
104 num_answers = ntohs(response.hdr.ancount);
|
meillo@0
|
105
|
meillo@0
|
106 return 0;
|
meillo@0
|
107 }
|
meillo@0
|
108
|
meillo@0
|
109 static int dns_next()
|
meillo@0
|
110 {
|
meillo@0
|
111 int i;
|
meillo@0
|
112
|
meillo@0
|
113 if (num_answers <= 0) return 2;
|
meillo@0
|
114 num_answers--;
|
meillo@0
|
115
|
meillo@0
|
116 if (resp_pos == resp_end)
|
meillo@0
|
117 return -1 /* soft */;
|
meillo@0
|
118
|
meillo@0
|
119 i = dn_expand(response.buf, resp_end, resp_pos, name, 256);
|
meillo@0
|
120 if (i < 0)
|
meillo@0
|
121 return -1; /* soft */
|
meillo@0
|
122 resp_pos += i;
|
meillo@0
|
123
|
meillo@0
|
124 i = resp_end - resp_pos;
|
meillo@0
|
125 if (i < 4 + 3 * 2)
|
meillo@0
|
126 return -1; /* soft */
|
meillo@0
|
127
|
meillo@0
|
128 rr_type = getshort(resp_pos);
|
meillo@0
|
129 rr_dlen = getshort(resp_pos + 8);
|
meillo@0
|
130 resp_pos += 10;
|
meillo@0
|
131
|
meillo@0
|
132 return 0;
|
meillo@0
|
133 }
|
meillo@0
|
134
|
meillo@0
|
135 static
|
meillo@0
|
136 int dns_getip(guint32 *ip)
|
meillo@0
|
137 {
|
meillo@0
|
138 int ret;
|
meillo@0
|
139
|
meillo@0
|
140 if((ret = dns_next())) return ret;
|
meillo@0
|
141
|
meillo@0
|
142 if (rr_type == T_A){
|
meillo@0
|
143 if (rr_dlen < 4)
|
meillo@0
|
144 return -1; /* soft */
|
meillo@0
|
145 *ip = *(guint32 *)(resp_pos);
|
meillo@0
|
146 DEBUG(5) debugf("DNS: dns_getip(): ip = %s\n", inet_ntoa(*(struct in_addr*)ip));
|
meillo@0
|
147 resp_pos += rr_dlen;
|
meillo@0
|
148
|
meillo@0
|
149 return 1;
|
meillo@0
|
150 }
|
meillo@0
|
151 resp_pos += rr_dlen;
|
meillo@0
|
152 return 0;
|
meillo@0
|
153 }
|
meillo@0
|
154
|
meillo@0
|
155 static
|
meillo@0
|
156 int dns_getmx(int *pref)
|
meillo@0
|
157 {
|
meillo@0
|
158 int ret;
|
meillo@0
|
159
|
meillo@0
|
160 if((ret = dns_next())) return ret;
|
meillo@0
|
161
|
meillo@0
|
162 if (rr_type == T_MX){
|
meillo@0
|
163 if (rr_dlen < 3)
|
meillo@0
|
164 return -1; /* soft */
|
meillo@0
|
165
|
meillo@0
|
166 *pref = (resp_pos[0] << 8) + resp_pos[1];
|
meillo@0
|
167 if (dn_expand(response.buf, resp_end, resp_pos + 2, name, MAX_DNSNAME) < 0)
|
meillo@0
|
168 return -1;
|
meillo@0
|
169
|
meillo@0
|
170 resp_pos += rr_dlen;
|
meillo@0
|
171
|
meillo@0
|
172 return 1;
|
meillo@0
|
173 }
|
meillo@0
|
174 resp_pos += rr_dlen;
|
meillo@0
|
175 return 0;
|
meillo@0
|
176 }
|
meillo@0
|
177
|
meillo@0
|
178 /*
|
meillo@0
|
179 static
|
meillo@0
|
180 int dns_getname(int type)
|
meillo@0
|
181 {
|
meillo@0
|
182 int ret;
|
meillo@0
|
183
|
meillo@0
|
184 if((ret = dns_next())) return ret;
|
meillo@0
|
185
|
meillo@0
|
186 if (rr_type == type){
|
meillo@0
|
187 if (dn_expand(response.buf, resp_end, resp_pos, name, MAX_DNSNAME) < 0)
|
meillo@0
|
188 return -1;
|
meillo@0
|
189
|
meillo@0
|
190 resp_pos += rr_dlen;
|
meillo@0
|
191
|
meillo@0
|
192 return 1;
|
meillo@0
|
193 }
|
meillo@0
|
194 resp_pos += rr_dlen;
|
meillo@0
|
195 return 0;
|
meillo@0
|
196 }
|
meillo@0
|
197 */
|
meillo@0
|
198
|
meillo@0
|
199 static
|
meillo@0
|
200 int dns_look_ip(gchar *domain, guint32 *ip)
|
meillo@0
|
201 {
|
meillo@0
|
202 gchar *n = domain;
|
meillo@0
|
203
|
meillo@0
|
204 while(TRUE){
|
meillo@0
|
205 if(dns_resolve(n, T_A, FALSE) == 0){
|
meillo@0
|
206 dns_next();
|
meillo@0
|
207 if(rr_type == T_A){
|
meillo@0
|
208 if (rr_dlen < 4)
|
meillo@0
|
209 return -1; /* soft */
|
meillo@0
|
210 *ip = *(guint32 *)(resp_pos);
|
meillo@0
|
211
|
meillo@0
|
212 DEBUG(5) debugf("DNS: dns_look_ip(): ip = %s\n",
|
meillo@0
|
213 inet_ntoa(*(struct in_addr*)ip));
|
meillo@0
|
214
|
meillo@0
|
215 resp_pos += rr_dlen;
|
meillo@0
|
216 return 0;
|
meillo@0
|
217 }else if(rr_type == T_CNAME){
|
meillo@0
|
218 if (dn_expand(response.buf, resp_end, resp_pos, name, MAX_DNSNAME) < 0)
|
meillo@0
|
219 return -1;
|
meillo@0
|
220
|
meillo@0
|
221 DEBUG(5) debugf("DNS: (CNAME) dns_look_ip(): name = %s\n", name);
|
meillo@0
|
222
|
meillo@0
|
223 resp_pos += rr_dlen;
|
meillo@0
|
224 n = name;
|
meillo@0
|
225 }else
|
meillo@0
|
226 return -1;
|
meillo@0
|
227 }else
|
meillo@0
|
228 return -1;
|
meillo@0
|
229 }
|
meillo@0
|
230 }
|
meillo@0
|
231
|
meillo@0
|
232 GList *resolve_dns_a(GList *list, gchar *domain)
|
meillo@0
|
233 {
|
meillo@0
|
234 int ret;
|
meillo@0
|
235
|
meillo@0
|
236 DEBUG(5) debugf("DNS: resolve_dns_a entered\n");
|
meillo@0
|
237
|
meillo@0
|
238 if(dns_resolve(domain, T_A, TRUE) == 0){
|
meillo@0
|
239 mxip_addr mxip;
|
meillo@0
|
240 while((ret = dns_getip(&(mxip.ip))) != 2){
|
meillo@0
|
241 if(ret == 1){
|
meillo@0
|
242 mxip.name = g_strdup(name);
|
meillo@0
|
243 mxip.pref = 0;
|
meillo@0
|
244 list = g_list_append(list, g_memdup(&mxip, sizeof(mxip)));
|
meillo@0
|
245 }
|
meillo@0
|
246 }
|
meillo@0
|
247 }
|
meillo@0
|
248 return list;
|
meillo@0
|
249 }
|
meillo@0
|
250
|
meillo@0
|
251 static
|
meillo@0
|
252 gint _mx_sort_func(gconstpointer aa, gconstpointer bb)
|
meillo@0
|
253 {
|
meillo@0
|
254 const mxip_addr *a = (mxip_addr *)aa;
|
meillo@0
|
255 const mxip_addr *b = (mxip_addr *)bb;
|
meillo@0
|
256
|
meillo@0
|
257 if(a->pref == b->pref)
|
meillo@0
|
258 return a->ip - b->ip;
|
meillo@0
|
259 else
|
meillo@0
|
260 return a->pref - b->pref;
|
meillo@0
|
261 }
|
meillo@0
|
262
|
meillo@0
|
263 GList *resolve_dns_mx(GList *list, gchar *domain)
|
meillo@0
|
264 {
|
meillo@0
|
265 GList *node;
|
meillo@0
|
266 int ret;
|
meillo@0
|
267 int cnt = 0;
|
meillo@0
|
268
|
meillo@0
|
269 DEBUG(5) debugf("DNS: resolve_dns_mx entered\n");
|
meillo@0
|
270
|
meillo@0
|
271 if(dns_resolve(domain, T_MX, TRUE) == 0){
|
meillo@0
|
272 GList *node_next;
|
meillo@0
|
273 mxip_addr mxip;
|
meillo@0
|
274 while((ret = dns_getmx(&(mxip.pref))) != 2){
|
meillo@0
|
275 if(ret == 1){
|
meillo@0
|
276 mxip.name = g_strdup(name);
|
meillo@0
|
277 mxip.ip = rand();
|
meillo@0
|
278 list = g_list_append(list, g_memdup(&mxip, sizeof(mxip)));
|
meillo@0
|
279 cnt++;
|
meillo@0
|
280 }
|
meillo@0
|
281 }
|
meillo@0
|
282
|
meillo@0
|
283 DEBUG(5) debugf("DNS: found %d mx records\n", cnt);
|
meillo@0
|
284
|
meillo@0
|
285 /* to randomize sequences with equal pref values,
|
meillo@0
|
286 we temporarily 'misused' the ip field and
|
meillo@0
|
287 put a random number in it as a secondary sort key.
|
meillo@0
|
288 */
|
meillo@0
|
289 list = g_list_sort(list, _mx_sort_func);
|
meillo@0
|
290
|
meillo@0
|
291 /* CNAME resolving has to be added as well. */
|
meillo@0
|
292
|
meillo@0
|
293 for(node = g_list_first(list);
|
meillo@0
|
294 node != NULL;
|
meillo@0
|
295 node = node_next){
|
meillo@0
|
296
|
meillo@0
|
297 mxip_addr *p_mxip = (mxip_addr *)(node->data);
|
meillo@0
|
298 node_next = g_list_next(node);
|
meillo@0
|
299
|
meillo@0
|
300 if(dns_look_ip(p_mxip->name, &(p_mxip->ip)) != 0){
|
meillo@0
|
301 DEBUG(1) debugf("DNS: could not resolve target of mx %s\n", p_mxip->name);
|
meillo@0
|
302 list = g_list_remove_link(list, node);
|
meillo@0
|
303 g_free(node->data);
|
meillo@0
|
304 g_list_free_1(node);
|
meillo@0
|
305 }
|
meillo@0
|
306 }
|
meillo@0
|
307 }
|
meillo@0
|
308 return list;
|
meillo@0
|
309 }
|
meillo@0
|
310
|
meillo@0
|
311 #endif
|
meillo@0
|
312
|
meillo@0
|
313 /* now something completely different... */
|
meillo@0
|
314
|
meillo@0
|
315 GList *resolve_byname(GList *list, gchar *domain)
|
meillo@0
|
316 {
|
meillo@0
|
317 struct hostent *hent;
|
meillo@0
|
318
|
meillo@0
|
319 DEBUG(5) debugf("DNS: resolve_byname entered\n");
|
meillo@0
|
320
|
meillo@0
|
321 if((hent = gethostbyname(domain))){
|
meillo@0
|
322 char *haddr;
|
meillo@0
|
323 int i = 0;
|
meillo@0
|
324 while((haddr = hent->h_addr_list[i++])){
|
meillo@0
|
325 mxip_addr mxip;
|
meillo@0
|
326 mxip.ip = *(guint32 *)(haddr);
|
meillo@0
|
327 mxip.pref = 0;
|
meillo@0
|
328 mxip.name = g_strdup(hent->h_name);
|
meillo@0
|
329 list = g_list_append(list, g_memdup(&mxip, sizeof(mxip)));
|
meillo@0
|
330 }
|
meillo@0
|
331 }
|
meillo@0
|
332 return list;
|
meillo@0
|
333 }
|
meillo@0
|
334
|
meillo@0
|
335 #ifdef RESOLV_TEST
|
meillo@0
|
336 int main(int argc, char *argv[])
|
meillo@0
|
337 {
|
meillo@0
|
338 GList *addr_list = NULL, *node;
|
meillo@0
|
339
|
meillo@0
|
340 g_print("starting res_init()\n");
|
meillo@0
|
341
|
meillo@0
|
342 g_print("retrans = %d, retry = %d\n", _res.retrans, _res.retry);
|
meillo@0
|
343
|
meillo@0
|
344 if(res_init() == 0){
|
meillo@0
|
345
|
meillo@0
|
346 addr_list = resolve_dns_a(NULL, argv[1]);
|
meillo@0
|
347 g_print("A:\n");
|
meillo@0
|
348
|
meillo@0
|
349 foreach(addr_list, node){
|
meillo@0
|
350 mxip_addr *p_mxip = (mxip_addr *)(node->data);
|
meillo@0
|
351
|
meillo@0
|
352 printf("name = %s\n IP = %s\n",
|
meillo@0
|
353 p_mxip->name,
|
meillo@0
|
354 inet_ntoa(*(struct in_addr *)&(p_mxip->ip)));
|
meillo@0
|
355 }
|
meillo@0
|
356 addr_list = resolve_dns_mx(NULL, argv[1]);
|
meillo@0
|
357 g_print("MX:\n");
|
meillo@0
|
358
|
meillo@0
|
359 foreach(addr_list, node){
|
meillo@0
|
360 mxip_addr *p_mxip = (mxip_addr *)(node->data);
|
meillo@0
|
361
|
meillo@0
|
362 printf("name = %s\n IP = %s pref = %d\n",
|
meillo@0
|
363 p_mxip->name,
|
meillo@0
|
364 inet_ntoa(*(struct in_addr *)&(p_mxip->ip)),
|
meillo@0
|
365 p_mxip->pref);
|
meillo@0
|
366 }
|
meillo@0
|
367 {
|
meillo@0
|
368 guint32 ip;
|
meillo@0
|
369 dns_look_ip(argv[1], &ip);
|
meillo@0
|
370 printf("dns_look_ip: %s\n", inet_ntoa(*((struct in_addr *)(&ip))));
|
meillo@0
|
371 }
|
meillo@0
|
372 }else
|
meillo@0
|
373 printf("res_init() failed.\n");
|
meillo@0
|
374
|
meillo@0
|
375 }
|
meillo@0
|
376 #endif
|