masqmail
view src/lookup.c @ 211:0f36c0a46f82
replaced hmac_md5.c with an own implementation of RFC 2104
Until now the sample code of the RFC itself was used,
but it lacked a license or copyright notice.
See the comment in hmac_md5.c for details.
author | meillo@marmaro.de |
---|---|
date | Sun, 18 Jul 2010 22:20:36 +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 }