masqmail

view src/lookup.c @ 262:fc1c6425c024

s/EXIT_SUCCESS/0/ && s/EXIT_FAILURE/1/ The constants are all to bulky. We should have different, meaningful exit codes anyway.
author markus schnalke <meillo@marmaro.de>
date Thu, 02 Dec 2010 17:11:25 -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 }