masqmail

view src/lookup.c @ 281:ea5f86e0a81c

modes are now enforced exclusive Other MTAs (exim, postfix) are more relaxing, but as combinations of exclusive modes are senseless we behave more obvious if we fail early. This makes understanding the behavior easier too.
author markus schnalke <meillo@marmaro.de>
date Tue, 07 Dec 2010 14:04:56 -0300
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 }