masqmail

view src/lookup.c @ 222:8cddc65765bd

added support for STARTTLS wrappers added the route config option `instant_helo' which causes masqmail, as SMTP client, not to wait for the server's 220 greeting. Instead if says EHLO right at once. You'll need this for STARTTLS wrappers that usually eat the greeting line.
author meillo@marmaro.de
date Fri, 23 Jul 2010 10:57:53 +0200
parents 138e66e1a61f
children 996b53a50f55
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"
26 #ifdef ENABLE_RESOLVER
28 static union {
29 HEADER hdr;
30 unsigned char buf[PACKETSZ];
31 } response;
32 static unsigned char *resp_end;
33 static unsigned char *resp_pos;
35 static int num_answers;
36 static char name[MAX_DNSNAME];
38 unsigned short rr_type;
39 unsigned short rr_dlen;
41 static unsigned short
42 getshort(unsigned char *c)
43 {
44 unsigned short u;
45 u = c[0];
46 return (u << 8) + c[1];
47 }
49 static int
50 dns_resolve(char *domain, int type, gboolean do_search)
51 {
52 int n;
53 int i;
54 int resp_len;
56 DEBUG(5) debugf("DNS: before res_search()\n");
57 if (do_search)
58 resp_len = res_search(domain, C_IN, type, response.buf, sizeof(response));
59 else
60 resp_len = res_query(domain, C_IN, type, response.buf, sizeof(response));
61 DEBUG(5) debugf("DBG: after res_search()\n");
63 if (resp_len <= 0) {
64 /*
65 if (errno == ECONNREFUSED) return DNS_SOFT;
66 if (h_errno == TRY_AGAIN) return DNS_SOFT;
67 return DNS_HARD;
68 */
69 return -1;
70 }
71 if (resp_len >= sizeof(response))
72 resp_len = sizeof(response);
74 resp_end = response.buf + resp_len;
75 resp_pos = response.buf + sizeof(HEADER);
76 n = ntohs(response.hdr.qdcount);
78 while (n-- > 0) {
79 i = dn_expand(response.buf, resp_end, resp_pos, name, MAX_DNSNAME);
80 if (i < 0)
81 return -1;
82 DEBUG(5) debugf("DBG: resolve name = %s\n", name);
83 resp_pos += i;
84 i = resp_end - resp_pos;
85 if (i < QFIXEDSZ)
86 return -1;
87 resp_pos += QFIXEDSZ;
88 }
89 num_answers = ntohs(response.hdr.ancount);
91 return 0;
92 }
94 static int
95 dns_next()
96 {
97 int i;
99 if (num_answers <= 0)
100 return 2;
101 num_answers--;
103 if (resp_pos == resp_end)
104 return -1; /* soft */
106 i = dn_expand(response.buf, resp_end, resp_pos, name, 256);
107 if (i < 0)
108 return -1; /* soft */
109 resp_pos += i;
111 i = resp_end - resp_pos;
112 if (i < 4 + 3 * 2)
113 return -1; /* soft */
115 rr_type = getshort(resp_pos);
116 rr_dlen = getshort(resp_pos + 8);
117 resp_pos += 10;
119 return 0;
120 }
122 static int
123 dns_getip(guint32 * ip)
124 {
125 int ret;
127 if ((ret = dns_next()))
128 return ret;
130 if (rr_type == T_A) {
131 if (rr_dlen < 4)
132 return -1; /* soft */
133 *ip = *(guint32 *) (resp_pos);
134 DEBUG(5) debugf("DNS: dns_getip(): ip = %s\n", inet_ntoa(*(struct in_addr *) ip));
135 resp_pos += rr_dlen;
137 return 1;
138 }
139 resp_pos += rr_dlen;
140 return 0;
141 }
143 static int
144 dns_getmx(int *pref)
145 {
146 int ret;
148 if ((ret = dns_next()))
149 return ret;
151 if (rr_type == T_MX) {
152 if (rr_dlen < 3)
153 return -1; /* soft */
155 *pref = (resp_pos[0] << 8) + resp_pos[1];
156 if (dn_expand(response.buf, resp_end, resp_pos + 2, name, MAX_DNSNAME) < 0)
157 return -1;
159 resp_pos += rr_dlen;
161 return 1;
162 }
163 resp_pos += rr_dlen;
164 return 0;
165 }
167 int
168 dns_look_ip(gchar * domain, guint32 * ip)
169 {
170 gchar *n = domain;
172 while (TRUE) {
173 if (dns_resolve(n, T_A, FALSE) != 0) {
174 return -1;
175 }
177 dns_next();
178 if (rr_type == T_A) {
179 if (rr_dlen < 4) {
180 return -1; /* soft */
181 }
182 *ip = *(guint32 *) (resp_pos);
184 DEBUG(5) debugf("DNS: dns_look_ip(): ip = %s\n", inet_ntoa(*(struct in_addr *) ip));
186 resp_pos += rr_dlen;
187 return 0;
188 } else if (rr_type == T_CNAME) {
189 if (dn_expand(response.buf, resp_end, resp_pos, name, MAX_DNSNAME) < 0) {
190 return -1;
191 }
193 DEBUG(5) debugf("DNS: (CNAME) dns_look_ip(): name = %s\n", name);
195 resp_pos += rr_dlen;
196 n = name;
197 } else {
198 return -1;
199 }
200 }
201 }
203 GList*
204 resolve_dns_a(GList * list, gchar * domain)
205 {
206 int ret;
208 DEBUG(5) debugf("DNS: resolve_dns_a entered\n");
210 if (dns_resolve(domain, T_A, TRUE) == 0) {
211 mxip_addr mxip;
212 while ((ret = dns_getip(&(mxip.ip))) != 2) {
213 if (ret == 1) {
214 mxip.name = g_strdup(name);
215 mxip.pref = 0;
216 list = g_list_append(list, g_memdup(&mxip, sizeof(mxip)));
217 }
218 }
219 }
220 return list;
221 }
223 static gint
224 _mx_sort_func(gconstpointer aa, gconstpointer bb)
225 {
226 const mxip_addr *a = (mxip_addr *) aa;
227 const mxip_addr *b = (mxip_addr *) bb;
229 if (a->pref == b->pref)
230 return a->ip - b->ip;
231 else
232 return a->pref - b->pref;
233 }
235 GList*
236 resolve_dns_mx(GList * list, gchar * domain)
237 {
238 GList *node;
239 int ret;
240 int cnt = 0;
242 DEBUG(5) debugf("DNS: resolve_dns_mx entered\n");
244 if (dns_resolve(domain, T_MX, TRUE) == 0) {
245 GList *node_next;
246 mxip_addr mxip;
247 while ((ret = dns_getmx(&(mxip.pref))) != 2) {
248 if (ret == 1) {
249 mxip.name = g_strdup(name);
250 mxip.ip = rand();
251 list = g_list_append(list, g_memdup(&mxip, sizeof(mxip)));
252 cnt++;
253 }
254 }
256 DEBUG(5) debugf("DNS: found %d mx records\n", cnt);
258 /* to randomize sequences with equal pref values,
259 we temporarily 'misused' the ip field and
260 put a random number in it as a secondary sort key.
261 */
262 list = g_list_sort(list, _mx_sort_func);
264 /* CNAME resolving has to be added as well. */
266 for (node = g_list_first(list); node != NULL; node = node_next) {
268 mxip_addr *p_mxip = (mxip_addr *) (node->data);
269 node_next = g_list_next(node);
271 if (dns_look_ip(p_mxip->name, &(p_mxip->ip)) != 0) {
272 DEBUG(1) debugf("DNS: could not resolve target of mx %s\n", p_mxip->name);
273 list = g_list_remove_link(list, node);
274 g_free(node->data);
275 g_list_free_1(node);
276 }
277 }
278 }
279 return list;
280 }
282 #endif
284 /* now something completely different... */
286 GList*
287 resolve_byname(GList * list, gchar * domain)
288 {
289 struct hostent *hent;
291 DEBUG(5) debugf("DNS: resolve_byname entered\n");
293 if ((hent = gethostbyname(domain))) {
294 char *haddr;
295 int i = 0;
296 while ((haddr = hent->h_addr_list[i++])) {
297 mxip_addr mxip;
298 mxip.ip = *(guint32 *) (haddr);
299 mxip.pref = 0;
300 mxip.name = g_strdup(hent->h_name);
301 list = g_list_append(list, g_memdup(&mxip, sizeof(mxip)));
302 }
303 }
304 return list;
305 }