masqmail-0.2

view src/lookup.c @ 179:ec3fe72a3e99

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