masqmail

view src/lookup.c @ 323:29de6a1c4538

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:47:27 +0200
parents dcb315792513
children 41958685480d
line source
1 /* MasqMail
2 * Copyright (C) Oliver Kurth
3 * Copyright (C) markus schnalke <meillo@marmaro.de>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
20 #include <sys/types.h>
21 #include <netinet/in.h>
22 #include <arpa/nameser.h>
23 #include <resolv.h>
25 #include "masqmail.h"
28 #ifdef ENABLE_RESOLVER
30 static union {
31 HEADER hdr;
32 unsigned char buf[PACKETSZ];
33 } response;
34 static unsigned char *resp_end;
35 static unsigned char *resp_pos;
37 static int num_answers;
38 static char name[MAX_DNSNAME];
40 unsigned short rr_type;
41 unsigned short rr_dlen;
43 static unsigned short
44 getshort(unsigned char *c)
45 {
46 unsigned short u;
47 u = c[0];
48 return (u << 8) + c[1];
49 }
51 static int
52 dns_resolve(char *domain, int type, gboolean do_search)
53 {
54 int n;
55 int i;
56 int resp_len;
58 DEBUG(5) debugf("DNS: before res_search()\n");
59 if (do_search)
60 resp_len = res_search(domain, C_IN, type, response.buf, sizeof(response));
61 else
62 resp_len = res_query(domain, C_IN, type, response.buf, sizeof(response));
63 DEBUG(5) debugf("DBG: after res_search()\n");
65 if (resp_len <= 0) {
66 /*
67 if (errno == ECONNREFUSED) return DNS_SOFT;
68 if (h_errno == TRY_AGAIN) return DNS_SOFT;
69 return DNS_HARD;
70 */
71 return -1;
72 }
73 if (resp_len >= sizeof(response))
74 resp_len = sizeof(response);
76 resp_end = response.buf + resp_len;
77 resp_pos = response.buf + sizeof(HEADER);
78 n = ntohs(response.hdr.qdcount);
80 while (n-- > 0) {
81 i = dn_expand(response.buf, resp_end, resp_pos, name, MAX_DNSNAME);
82 if (i < 0)
83 return -1;
84 DEBUG(5) debugf("DBG: resolve name = %s\n", name);
85 resp_pos += i;
86 i = resp_end - resp_pos;
87 if (i < QFIXEDSZ)
88 return -1;
89 resp_pos += QFIXEDSZ;
90 }
91 num_answers = ntohs(response.hdr.ancount);
93 return 0;
94 }
96 static int
97 dns_next()
98 {
99 int i;
101 if (num_answers <= 0)
102 return 2;
103 num_answers--;
105 if (resp_pos == resp_end)
106 return -1; /* soft */
108 i = dn_expand(response.buf, resp_end, resp_pos, name, 256);
109 if (i < 0)
110 return -1; /* soft */
111 resp_pos += i;
113 i = resp_end - resp_pos;
114 if (i < 4 + 3 * 2)
115 return -1; /* soft */
117 rr_type = getshort(resp_pos);
118 rr_dlen = getshort(resp_pos + 8);
119 resp_pos += 10;
121 return 0;
122 }
124 static int
125 dns_getip(guint32 * ip)
126 {
127 int ret;
129 if ((ret = dns_next()))
130 return ret;
132 if (rr_type == T_A) {
133 if (rr_dlen < 4)
134 return -1; /* soft */
135 *ip = *(guint32 *) (resp_pos);
136 DEBUG(5) debugf("DNS: dns_getip(): ip = %s\n", inet_ntoa(*(struct in_addr *) ip));
137 resp_pos += rr_dlen;
139 return 1;
140 }
141 resp_pos += rr_dlen;
142 return 0;
143 }
145 static int
146 dns_getmx(int *pref)
147 {
148 int ret;
150 if ((ret = dns_next()))
151 return ret;
153 if (rr_type == T_MX) {
154 if (rr_dlen < 3)
155 return -1; /* soft */
157 *pref = (resp_pos[0] << 8) + resp_pos[1];
158 if (dn_expand(response.buf, resp_end, resp_pos + 2, name, MAX_DNSNAME) < 0)
159 return -1;
161 resp_pos += rr_dlen;
163 return 1;
164 }
165 resp_pos += rr_dlen;
166 return 0;
167 }
169 int
170 dns_look_ip(gchar * domain, guint32 * ip)
171 {
172 gchar *n = domain;
174 while (TRUE) {
175 if (dns_resolve(n, T_A, FALSE) != 0) {
176 return -1;
177 }
179 dns_next();
180 if (rr_type == T_A) {
181 if (rr_dlen < 4) {
182 return -1; /* soft */
183 }
184 *ip = *(guint32 *) (resp_pos);
186 DEBUG(5) debugf("DNS: dns_look_ip(): ip = %s\n", inet_ntoa(*(struct in_addr *) ip));
188 resp_pos += rr_dlen;
189 return 0;
190 } else if (rr_type == T_CNAME) {
191 if (dn_expand(response.buf, resp_end, resp_pos, name, MAX_DNSNAME) < 0) {
192 return -1;
193 }
195 DEBUG(5) debugf("DNS: (CNAME) dns_look_ip(): name = %s\n", name);
197 resp_pos += rr_dlen;
198 n = name;
199 } else {
200 return -1;
201 }
202 }
203 }
205 GList*
206 resolve_dns_a(GList * list, gchar * domain)
207 {
208 int ret;
210 DEBUG(5) debugf("DNS: resolve_dns_a entered\n");
212 if (dns_resolve(domain, T_A, TRUE) == 0) {
213 mxip_addr mxip;
214 while ((ret = dns_getip(&(mxip.ip))) != 2) {
215 if (ret == 1) {
216 mxip.name = g_strdup(name);
217 mxip.pref = 0;
218 list = g_list_append(list, g_memdup(&mxip, sizeof(mxip)));
219 }
220 }
221 }
222 return list;
223 }
225 static gint
226 _mx_sort_func(gconstpointer aa, gconstpointer bb)
227 {
228 const mxip_addr *a = (mxip_addr *) aa;
229 const mxip_addr *b = (mxip_addr *) bb;
231 if (a->pref == b->pref)
232 return a->ip - b->ip;
233 else
234 return a->pref - b->pref;
235 }
237 GList*
238 resolve_dns_mx(GList * list, gchar * domain)
239 {
240 GList *node;
241 int ret;
242 int cnt = 0;
244 DEBUG(5) debugf("DNS: resolve_dns_mx entered\n");
246 if (dns_resolve(domain, T_MX, TRUE) == 0) {
247 GList *node_next;
248 mxip_addr mxip;
249 while ((ret = dns_getmx(&(mxip.pref))) != 2) {
250 if (ret == 1) {
251 mxip.name = g_strdup(name);
252 mxip.ip = rand();
253 list = g_list_append(list, g_memdup(&mxip, sizeof(mxip)));
254 cnt++;
255 }
256 }
258 DEBUG(5) debugf("DNS: found %d mx records\n", cnt);
260 /* to randomize sequences with equal pref values,
261 we temporarily 'misused' the ip field and
262 put a random number in it as a secondary sort key.
263 */
264 list = g_list_sort(list, _mx_sort_func);
266 /* CNAME resolving has to be added as well. */
268 for (node = g_list_first(list); node != NULL; node = node_next) {
270 mxip_addr *p_mxip = (mxip_addr *) (node->data);
271 node_next = g_list_next(node);
273 if (dns_look_ip(p_mxip->name, &(p_mxip->ip)) != 0) {
274 DEBUG(1) debugf("DNS: could not resolve target of mx %s\n", p_mxip->name);
275 list = g_list_remove_link(list, node);
276 g_free(node->data);
277 g_list_free_1(node);
278 }
279 }
280 }
281 return list;
282 }
284 #endif
286 /* now something completely different... */
288 GList*
289 resolve_byname(GList * list, gchar * domain)
290 {
291 struct hostent *hent;
293 DEBUG(5) debugf("DNS: resolve_byname entered\n");
295 if ((hent = gethostbyname(domain))) {
296 char *haddr;
297 int i = 0;
298 while ((haddr = hent->h_addr_list[i++])) {
299 mxip_addr mxip;
300 mxip.ip = *(guint32 *) (haddr);
301 mxip.pref = 0;
302 mxip.name = g_strdup(hent->h_name);
303 list = g_list_append(list, g_memdup(&mxip, sizeof(mxip)));
304 }
305 }
306 return list;
307 }