masqmail-0.2
diff src/lookup.c @ 0:08114f7dcc23
this is masqmail-0.2.21 from oliver kurth
author | meillo@marmaro.de |
---|---|
date | Fri, 26 Sep 2008 17:05:23 +0200 |
parents | |
children | 26e34ae9a3e3 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/lookup.c Fri Sep 26 17:05:23 2008 +0200 1.3 @@ -0,0 +1,376 @@ 1.4 +/* MasqMail Copyright (C) Oliver Kurth, 1.5 + * 1.6 + * This program is free software; you can redistribute it and/or modify 1.7 + * it under the terms of the GNU General Public License as published by 1.8 + * the Free Software Foundation; either version 2 of the License, or 1.9 + * (at your option) any later version. 1.10 + * 1.11 + * This program is distributed in the hope that it will be useful, 1.12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 1.13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.14 + * GNU General Public License for more details. 1.15 + * 1.16 + * You should have received a copy of the GNU General Public License 1.17 + * along with this program; if not, write to the Free Software 1.18 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 1.19 + */ 1.20 + 1.21 +#include <sys/types.h> 1.22 +#include <netinet/in.h> 1.23 +#include <arpa/nameser.h> 1.24 +#include <resolv.h> 1.25 + 1.26 +#include "masqmail.h" 1.27 + 1.28 +#ifdef RESOLV_TEST 1.29 + 1.30 +#undef DEBUG 1.31 +#define DEBUG(x) if(x > 0) 1.32 + 1.33 +#define debugf g_print 1.34 +#endif 1.35 + 1.36 +#ifdef ENABLE_RESOLVER 1.37 + 1.38 +static union { 1.39 + HEADER hdr; 1.40 + unsigned char buf[PACKETSZ]; 1.41 +} response; 1.42 +static unsigned char *resp_end; 1.43 +static unsigned char *resp_pos; 1.44 + 1.45 +static int num_answers; 1.46 +static char name[MAX_DNSNAME]; 1.47 + 1.48 +unsigned short rr_type; 1.49 +unsigned short rr_dlen; 1.50 + 1.51 +static 1.52 +unsigned short getshort(unsigned char *c) 1.53 +{ 1.54 + unsigned short u; 1.55 + u = c[0]; 1.56 + return (u << 8) + c[1]; 1.57 +} 1.58 + 1.59 +static 1.60 +int dns_resolve(char *domain, int type, gboolean do_search) 1.61 +{ 1.62 + int n; 1.63 + int i; 1.64 + 1.65 + int resp_len; 1.66 + /*errno = 0;*/ 1.67 + 1.68 + /* 1.69 + if (!stralloc_copy(&glue,domain)) return DNS_MEM; 1.70 + if (!stralloc_0(&glue)) return DNS_MEM; 1.71 + */ 1.72 + 1.73 + // resp_len = res_query(domain, C_IN, type, response.buf, sizeof(response)); 1.74 + DEBUG(5) debugf("DNS: before res_search()\n"); 1.75 + if(do_search) 1.76 + resp_len = res_search(domain, C_IN, type, response.buf, sizeof(response)); 1.77 + else 1.78 + resp_len = res_query(domain, C_IN, type, response.buf, sizeof(response)); 1.79 + DEBUG(5) debugf("DBG: after res_search()\n"); 1.80 + 1.81 + if (resp_len <= 0){ 1.82 + /* 1.83 + if (errno == ECONNREFUSED) return DNS_SOFT; 1.84 + if (h_errno == TRY_AGAIN) return DNS_SOFT; 1.85 + return DNS_HARD; 1.86 + */ 1.87 + return -1; 1.88 + } 1.89 + if (resp_len >= sizeof(response)) 1.90 + resp_len = sizeof(response); 1.91 + 1.92 + resp_end = response.buf + resp_len; 1.93 + resp_pos = response.buf + sizeof(HEADER); 1.94 + n = ntohs(response.hdr.qdcount); 1.95 + 1.96 + while (n-- > 0){ 1.97 + i = dn_expand(response.buf, resp_end, resp_pos, name, MAX_DNSNAME); 1.98 + if (i < 0) 1.99 + return -1; 1.100 + DEBUG(5) debugf("DBG: resolve name = %s\n", name); 1.101 + resp_pos += i; 1.102 + i = resp_end - resp_pos; 1.103 + if (i < QFIXEDSZ) 1.104 + return -1; 1.105 + resp_pos += QFIXEDSZ; 1.106 + } 1.107 + num_answers = ntohs(response.hdr.ancount); 1.108 + 1.109 + return 0; 1.110 +} 1.111 + 1.112 +static int dns_next() 1.113 +{ 1.114 + int i; 1.115 + 1.116 + if (num_answers <= 0) return 2; 1.117 + num_answers--; 1.118 + 1.119 + if (resp_pos == resp_end) 1.120 + return -1 /* soft */; 1.121 + 1.122 + i = dn_expand(response.buf, resp_end, resp_pos, name, 256); 1.123 + if (i < 0) 1.124 + return -1; /* soft */ 1.125 + resp_pos += i; 1.126 + 1.127 + i = resp_end - resp_pos; 1.128 + if (i < 4 + 3 * 2) 1.129 + return -1; /* soft */ 1.130 + 1.131 + rr_type = getshort(resp_pos); 1.132 + rr_dlen = getshort(resp_pos + 8); 1.133 + resp_pos += 10; 1.134 + 1.135 + return 0; 1.136 +} 1.137 + 1.138 +static 1.139 +int dns_getip(guint32 *ip) 1.140 +{ 1.141 + int ret; 1.142 + 1.143 + if((ret = dns_next())) return ret; 1.144 + 1.145 + if (rr_type == T_A){ 1.146 + if (rr_dlen < 4) 1.147 + return -1; /* soft */ 1.148 + *ip = *(guint32 *)(resp_pos); 1.149 + DEBUG(5) debugf("DNS: dns_getip(): ip = %s\n", inet_ntoa(*(struct in_addr*)ip)); 1.150 + resp_pos += rr_dlen; 1.151 + 1.152 + return 1; 1.153 + } 1.154 + resp_pos += rr_dlen; 1.155 + return 0; 1.156 +} 1.157 + 1.158 +static 1.159 +int dns_getmx(int *pref) 1.160 +{ 1.161 + int ret; 1.162 + 1.163 + if((ret = dns_next())) return ret; 1.164 + 1.165 + if (rr_type == T_MX){ 1.166 + if (rr_dlen < 3) 1.167 + return -1; /* soft */ 1.168 + 1.169 + *pref = (resp_pos[0] << 8) + resp_pos[1]; 1.170 + if (dn_expand(response.buf, resp_end, resp_pos + 2, name, MAX_DNSNAME) < 0) 1.171 + return -1; 1.172 + 1.173 + resp_pos += rr_dlen; 1.174 + 1.175 + return 1; 1.176 + } 1.177 + resp_pos += rr_dlen; 1.178 + return 0; 1.179 +} 1.180 + 1.181 +/* 1.182 +static 1.183 +int dns_getname(int type) 1.184 +{ 1.185 + int ret; 1.186 + 1.187 + if((ret = dns_next())) return ret; 1.188 + 1.189 + if (rr_type == type){ 1.190 + if (dn_expand(response.buf, resp_end, resp_pos, name, MAX_DNSNAME) < 0) 1.191 + return -1; 1.192 + 1.193 + resp_pos += rr_dlen; 1.194 + 1.195 + return 1; 1.196 + } 1.197 + resp_pos += rr_dlen; 1.198 + return 0; 1.199 +} 1.200 +*/ 1.201 + 1.202 +static 1.203 +int dns_look_ip(gchar *domain, guint32 *ip) 1.204 +{ 1.205 + gchar *n = domain; 1.206 + 1.207 + while(TRUE){ 1.208 + if(dns_resolve(n, T_A, FALSE) == 0){ 1.209 + dns_next(); 1.210 + if(rr_type == T_A){ 1.211 + if (rr_dlen < 4) 1.212 + return -1; /* soft */ 1.213 + *ip = *(guint32 *)(resp_pos); 1.214 + 1.215 + DEBUG(5) debugf("DNS: dns_look_ip(): ip = %s\n", 1.216 + inet_ntoa(*(struct in_addr*)ip)); 1.217 + 1.218 + resp_pos += rr_dlen; 1.219 + return 0; 1.220 + }else if(rr_type == T_CNAME){ 1.221 + if (dn_expand(response.buf, resp_end, resp_pos, name, MAX_DNSNAME) < 0) 1.222 + return -1; 1.223 + 1.224 + DEBUG(5) debugf("DNS: (CNAME) dns_look_ip(): name = %s\n", name); 1.225 + 1.226 + resp_pos += rr_dlen; 1.227 + n = name; 1.228 + }else 1.229 + return -1; 1.230 + }else 1.231 + return -1; 1.232 + } 1.233 +} 1.234 + 1.235 +GList *resolve_dns_a(GList *list, gchar *domain) 1.236 +{ 1.237 + int ret; 1.238 + 1.239 + DEBUG(5) debugf("DNS: resolve_dns_a entered\n"); 1.240 + 1.241 + if(dns_resolve(domain, T_A, TRUE) == 0){ 1.242 + mxip_addr mxip; 1.243 + while((ret = dns_getip(&(mxip.ip))) != 2){ 1.244 + if(ret == 1){ 1.245 + mxip.name = g_strdup(name); 1.246 + mxip.pref = 0; 1.247 + list = g_list_append(list, g_memdup(&mxip, sizeof(mxip))); 1.248 + } 1.249 + } 1.250 + } 1.251 + return list; 1.252 +} 1.253 + 1.254 +static 1.255 +gint _mx_sort_func(gconstpointer aa, gconstpointer bb) 1.256 +{ 1.257 + const mxip_addr *a = (mxip_addr *)aa; 1.258 + const mxip_addr *b = (mxip_addr *)bb; 1.259 + 1.260 + if(a->pref == b->pref) 1.261 + return a->ip - b->ip; 1.262 + else 1.263 + return a->pref - b->pref; 1.264 +} 1.265 + 1.266 +GList *resolve_dns_mx(GList *list, gchar *domain) 1.267 +{ 1.268 + GList *node; 1.269 + int ret; 1.270 + int cnt = 0; 1.271 + 1.272 + DEBUG(5) debugf("DNS: resolve_dns_mx entered\n"); 1.273 + 1.274 + if(dns_resolve(domain, T_MX, TRUE) == 0){ 1.275 + GList *node_next; 1.276 + mxip_addr mxip; 1.277 + while((ret = dns_getmx(&(mxip.pref))) != 2){ 1.278 + if(ret == 1){ 1.279 + mxip.name = g_strdup(name); 1.280 + mxip.ip = rand(); 1.281 + list = g_list_append(list, g_memdup(&mxip, sizeof(mxip))); 1.282 + cnt++; 1.283 + } 1.284 + } 1.285 + 1.286 + DEBUG(5) debugf("DNS: found %d mx records\n", cnt); 1.287 + 1.288 + /* to randomize sequences with equal pref values, 1.289 + we temporarily 'misused' the ip field and 1.290 + put a random number in it as a secondary sort key. 1.291 + */ 1.292 + list = g_list_sort(list, _mx_sort_func); 1.293 + 1.294 + /* CNAME resolving has to be added as well. */ 1.295 + 1.296 + for(node = g_list_first(list); 1.297 + node != NULL; 1.298 + node = node_next){ 1.299 + 1.300 + mxip_addr *p_mxip = (mxip_addr *)(node->data); 1.301 + node_next = g_list_next(node); 1.302 + 1.303 + if(dns_look_ip(p_mxip->name, &(p_mxip->ip)) != 0){ 1.304 + DEBUG(1) debugf("DNS: could not resolve target of mx %s\n", p_mxip->name); 1.305 + list = g_list_remove_link(list, node); 1.306 + g_free(node->data); 1.307 + g_list_free_1(node); 1.308 + } 1.309 + } 1.310 + } 1.311 + return list; 1.312 +} 1.313 + 1.314 +#endif 1.315 + 1.316 +/* now something completely different... */ 1.317 + 1.318 +GList *resolve_byname(GList *list, gchar *domain) 1.319 +{ 1.320 + struct hostent *hent; 1.321 + 1.322 + DEBUG(5) debugf("DNS: resolve_byname entered\n"); 1.323 + 1.324 + if((hent = gethostbyname(domain))){ 1.325 + char *haddr; 1.326 + int i = 0; 1.327 + while((haddr = hent->h_addr_list[i++])){ 1.328 + mxip_addr mxip; 1.329 + mxip.ip = *(guint32 *)(haddr); 1.330 + mxip.pref = 0; 1.331 + mxip.name = g_strdup(hent->h_name); 1.332 + list = g_list_append(list, g_memdup(&mxip, sizeof(mxip))); 1.333 + } 1.334 + } 1.335 + return list; 1.336 +} 1.337 + 1.338 +#ifdef RESOLV_TEST 1.339 +int main(int argc, char *argv[]) 1.340 +{ 1.341 + GList *addr_list = NULL, *node; 1.342 + 1.343 + g_print("starting res_init()\n"); 1.344 + 1.345 + g_print("retrans = %d, retry = %d\n", _res.retrans, _res.retry); 1.346 + 1.347 + if(res_init() == 0){ 1.348 + 1.349 + addr_list = resolve_dns_a(NULL, argv[1]); 1.350 + g_print("A:\n"); 1.351 + 1.352 + foreach(addr_list, node){ 1.353 + mxip_addr *p_mxip = (mxip_addr *)(node->data); 1.354 + 1.355 + printf("name = %s\n IP = %s\n", 1.356 + p_mxip->name, 1.357 + inet_ntoa(*(struct in_addr *)&(p_mxip->ip))); 1.358 + } 1.359 + addr_list = resolve_dns_mx(NULL, argv[1]); 1.360 + g_print("MX:\n"); 1.361 + 1.362 + foreach(addr_list, node){ 1.363 + mxip_addr *p_mxip = (mxip_addr *)(node->data); 1.364 + 1.365 + printf("name = %s\n IP = %s pref = %d\n", 1.366 + p_mxip->name, 1.367 + inet_ntoa(*(struct in_addr *)&(p_mxip->ip)), 1.368 + p_mxip->pref); 1.369 + } 1.370 + { 1.371 + guint32 ip; 1.372 + dns_look_ip(argv[1], &ip); 1.373 + printf("dns_look_ip: %s\n", inet_ntoa(*((struct in_addr *)(&ip)))); 1.374 + } 1.375 + }else 1.376 + printf("res_init() failed.\n"); 1.377 + 1.378 +} 1.379 +#endif