masqmail

annotate 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
rev   line source
meillo@224 1 /* MasqMail
meillo@224 2 * Copyright (C) Oliver Kurth
meillo@224 3 * Copyright (C) markus schnalke <meillo@marmaro.de>
meillo@0 4 *
meillo@0 5 * This program is free software; you can redistribute it and/or modify
meillo@0 6 * it under the terms of the GNU General Public License as published by
meillo@0 7 * the Free Software Foundation; either version 2 of the License, or
meillo@0 8 * (at your option) any later version.
meillo@10 9 *
meillo@0 10 * This program is distributed in the hope that it will be useful,
meillo@0 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
meillo@0 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
meillo@0 13 * GNU General Public License for more details.
meillo@0 14 *
meillo@0 15 * You should have received a copy of the GNU General Public License
meillo@0 16 * along with this program; if not, write to the Free Software
meillo@0 17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
meillo@0 18 */
meillo@0 19
meillo@0 20 #include <sys/types.h>
meillo@0 21 #include <netinet/in.h>
meillo@0 22 #include <arpa/nameser.h>
meillo@0 23 #include <resolv.h>
meillo@0 24
meillo@0 25 #include "masqmail.h"
meillo@0 26
meillo@0 27
meillo@0 28 #ifdef ENABLE_RESOLVER
meillo@0 29
meillo@0 30 static union {
meillo@10 31 HEADER hdr;
meillo@10 32 unsigned char buf[PACKETSZ];
meillo@0 33 } response;
meillo@0 34 static unsigned char *resp_end;
meillo@0 35 static unsigned char *resp_pos;
meillo@0 36
meillo@0 37 static int num_answers;
meillo@0 38 static char name[MAX_DNSNAME];
meillo@0 39
meillo@0 40 unsigned short rr_type;
meillo@0 41 unsigned short rr_dlen;
meillo@0 42
meillo@10 43 static unsigned short
meillo@10 44 getshort(unsigned char *c)
meillo@0 45 {
meillo@10 46 unsigned short u;
meillo@10 47 u = c[0];
meillo@10 48 return (u << 8) + c[1];
meillo@0 49 }
meillo@0 50
meillo@10 51 static int
meillo@10 52 dns_resolve(char *domain, int type, gboolean do_search)
meillo@0 53 {
meillo@10 54 int n;
meillo@10 55 int i;
meillo@207 56 int resp_len;
meillo@0 57
meillo@10 58 DEBUG(5) debugf("DNS: before res_search()\n");
meillo@10 59 if (do_search)
meillo@10 60 resp_len = res_search(domain, C_IN, type, response.buf, sizeof(response));
meillo@10 61 else
meillo@10 62 resp_len = res_query(domain, C_IN, type, response.buf, sizeof(response));
meillo@10 63 DEBUG(5) debugf("DBG: after res_search()\n");
meillo@0 64
meillo@10 65 if (resp_len <= 0) {
meillo@10 66 /*
meillo@10 67 if (errno == ECONNREFUSED) return DNS_SOFT;
meillo@10 68 if (h_errno == TRY_AGAIN) return DNS_SOFT;
meillo@10 69 return DNS_HARD;
meillo@10 70 */
meillo@10 71 return -1;
meillo@10 72 }
meillo@10 73 if (resp_len >= sizeof(response))
meillo@10 74 resp_len = sizeof(response);
meillo@0 75
meillo@10 76 resp_end = response.buf + resp_len;
meillo@10 77 resp_pos = response.buf + sizeof(HEADER);
meillo@10 78 n = ntohs(response.hdr.qdcount);
meillo@0 79
meillo@10 80 while (n-- > 0) {
meillo@10 81 i = dn_expand(response.buf, resp_end, resp_pos, name, MAX_DNSNAME);
meillo@10 82 if (i < 0)
meillo@10 83 return -1;
meillo@10 84 DEBUG(5) debugf("DBG: resolve name = %s\n", name);
meillo@10 85 resp_pos += i;
meillo@10 86 i = resp_end - resp_pos;
meillo@10 87 if (i < QFIXEDSZ)
meillo@10 88 return -1;
meillo@10 89 resp_pos += QFIXEDSZ;
meillo@10 90 }
meillo@10 91 num_answers = ntohs(response.hdr.ancount);
meillo@0 92
meillo@10 93 return 0;
meillo@0 94 }
meillo@0 95
meillo@10 96 static int
meillo@10 97 dns_next()
meillo@0 98 {
meillo@10 99 int i;
meillo@0 100
meillo@10 101 if (num_answers <= 0)
meillo@10 102 return 2;
meillo@10 103 num_answers--;
meillo@0 104
meillo@10 105 if (resp_pos == resp_end)
meillo@10 106 return -1; /* soft */
meillo@0 107
meillo@10 108 i = dn_expand(response.buf, resp_end, resp_pos, name, 256);
meillo@10 109 if (i < 0)
meillo@10 110 return -1; /* soft */
meillo@10 111 resp_pos += i;
meillo@0 112
meillo@10 113 i = resp_end - resp_pos;
meillo@10 114 if (i < 4 + 3 * 2)
meillo@10 115 return -1; /* soft */
meillo@0 116
meillo@10 117 rr_type = getshort(resp_pos);
meillo@10 118 rr_dlen = getshort(resp_pos + 8);
meillo@10 119 resp_pos += 10;
meillo@10 120
meillo@10 121 return 0;
meillo@0 122 }
meillo@0 123
meillo@10 124 static int
meillo@10 125 dns_getip(guint32 * ip)
meillo@0 126 {
meillo@10 127 int ret;
meillo@0 128
meillo@10 129 if ((ret = dns_next()))
meillo@10 130 return ret;
meillo@0 131
meillo@10 132 if (rr_type == T_A) {
meillo@10 133 if (rr_dlen < 4)
meillo@10 134 return -1; /* soft */
meillo@10 135 *ip = *(guint32 *) (resp_pos);
meillo@10 136 DEBUG(5) debugf("DNS: dns_getip(): ip = %s\n", inet_ntoa(*(struct in_addr *) ip));
meillo@10 137 resp_pos += rr_dlen;
meillo@0 138
meillo@10 139 return 1;
meillo@10 140 }
meillo@10 141 resp_pos += rr_dlen;
meillo@10 142 return 0;
meillo@0 143 }
meillo@0 144
meillo@10 145 static int
meillo@10 146 dns_getmx(int *pref)
meillo@0 147 {
meillo@10 148 int ret;
meillo@0 149
meillo@10 150 if ((ret = dns_next()))
meillo@10 151 return ret;
meillo@0 152
meillo@10 153 if (rr_type == T_MX) {
meillo@10 154 if (rr_dlen < 3)
meillo@10 155 return -1; /* soft */
meillo@0 156
meillo@10 157 *pref = (resp_pos[0] << 8) + resp_pos[1];
meillo@10 158 if (dn_expand(response.buf, resp_end, resp_pos + 2, name, MAX_DNSNAME) < 0)
meillo@10 159 return -1;
meillo@0 160
meillo@10 161 resp_pos += rr_dlen;
meillo@10 162
meillo@10 163 return 1;
meillo@10 164 }
meillo@10 165 resp_pos += rr_dlen;
meillo@10 166 return 0;
meillo@0 167 }
meillo@0 168
meillo@200 169 int
meillo@10 170 dns_look_ip(gchar * domain, guint32 * ip)
meillo@0 171 {
meillo@10 172 gchar *n = domain;
meillo@0 173
meillo@10 174 while (TRUE) {
meillo@200 175 if (dns_resolve(n, T_A, FALSE) != 0) {
meillo@200 176 return -1;
meillo@200 177 }
meillo@0 178
meillo@200 179 dns_next();
meillo@200 180 if (rr_type == T_A) {
meillo@200 181 if (rr_dlen < 4) {
meillo@200 182 return -1; /* soft */
meillo@200 183 }
meillo@200 184 *ip = *(guint32 *) (resp_pos);
meillo@10 185
meillo@200 186 DEBUG(5) debugf("DNS: dns_look_ip(): ip = %s\n", inet_ntoa(*(struct in_addr *) ip));
meillo@10 187
meillo@200 188 resp_pos += rr_dlen;
meillo@200 189 return 0;
meillo@200 190 } else if (rr_type == T_CNAME) {
meillo@200 191 if (dn_expand(response.buf, resp_end, resp_pos, name, MAX_DNSNAME) < 0) {
meillo@200 192 return -1;
meillo@200 193 }
meillo@10 194
meillo@200 195 DEBUG(5) debugf("DNS: (CNAME) dns_look_ip(): name = %s\n", name);
meillo@200 196
meillo@200 197 resp_pos += rr_dlen;
meillo@200 198 n = name;
meillo@200 199 } else {
meillo@10 200 return -1;
meillo@200 201 }
meillo@10 202 }
meillo@0 203 }
meillo@0 204
meillo@10 205 GList*
meillo@10 206 resolve_dns_a(GList * list, gchar * domain)
meillo@0 207 {
meillo@10 208 int ret;
meillo@0 209
meillo@10 210 DEBUG(5) debugf("DNS: resolve_dns_a entered\n");
meillo@0 211
meillo@10 212 if (dns_resolve(domain, T_A, TRUE) == 0) {
meillo@10 213 mxip_addr mxip;
meillo@10 214 while ((ret = dns_getip(&(mxip.ip))) != 2) {
meillo@10 215 if (ret == 1) {
meillo@10 216 mxip.name = g_strdup(name);
meillo@10 217 mxip.pref = 0;
meillo@10 218 list = g_list_append(list, g_memdup(&mxip, sizeof(mxip)));
meillo@10 219 }
meillo@10 220 }
meillo@10 221 }
meillo@10 222 return list;
meillo@0 223 }
meillo@0 224
meillo@10 225 static gint
meillo@10 226 _mx_sort_func(gconstpointer aa, gconstpointer bb)
meillo@0 227 {
meillo@10 228 const mxip_addr *a = (mxip_addr *) aa;
meillo@10 229 const mxip_addr *b = (mxip_addr *) bb;
meillo@0 230
meillo@10 231 if (a->pref == b->pref)
meillo@10 232 return a->ip - b->ip;
meillo@10 233 else
meillo@10 234 return a->pref - b->pref;
meillo@0 235 }
meillo@0 236
meillo@10 237 GList*
meillo@10 238 resolve_dns_mx(GList * list, gchar * domain)
meillo@0 239 {
meillo@10 240 GList *node;
meillo@10 241 int ret;
meillo@10 242 int cnt = 0;
meillo@0 243
meillo@10 244 DEBUG(5) debugf("DNS: resolve_dns_mx entered\n");
meillo@0 245
meillo@10 246 if (dns_resolve(domain, T_MX, TRUE) == 0) {
meillo@10 247 GList *node_next;
meillo@10 248 mxip_addr mxip;
meillo@10 249 while ((ret = dns_getmx(&(mxip.pref))) != 2) {
meillo@10 250 if (ret == 1) {
meillo@10 251 mxip.name = g_strdup(name);
meillo@10 252 mxip.ip = rand();
meillo@10 253 list = g_list_append(list, g_memdup(&mxip, sizeof(mxip)));
meillo@10 254 cnt++;
meillo@10 255 }
meillo@10 256 }
meillo@0 257
meillo@10 258 DEBUG(5) debugf("DNS: found %d mx records\n", cnt);
meillo@0 259
meillo@10 260 /* to randomize sequences with equal pref values,
meillo@10 261 we temporarily 'misused' the ip field and
meillo@10 262 put a random number in it as a secondary sort key.
meillo@10 263 */
meillo@10 264 list = g_list_sort(list, _mx_sort_func);
meillo@0 265
meillo@10 266 /* CNAME resolving has to be added as well. */
meillo@0 267
meillo@10 268 for (node = g_list_first(list); node != NULL; node = node_next) {
meillo@0 269
meillo@10 270 mxip_addr *p_mxip = (mxip_addr *) (node->data);
meillo@10 271 node_next = g_list_next(node);
meillo@0 272
meillo@10 273 if (dns_look_ip(p_mxip->name, &(p_mxip->ip)) != 0) {
meillo@10 274 DEBUG(1) debugf("DNS: could not resolve target of mx %s\n", p_mxip->name);
meillo@10 275 list = g_list_remove_link(list, node);
meillo@10 276 g_free(node->data);
meillo@10 277 g_list_free_1(node);
meillo@10 278 }
meillo@10 279 }
meillo@10 280 }
meillo@10 281 return list;
meillo@0 282 }
meillo@0 283
meillo@0 284 #endif
meillo@0 285
meillo@0 286 /* now something completely different... */
meillo@0 287
meillo@10 288 GList*
meillo@10 289 resolve_byname(GList * list, gchar * domain)
meillo@0 290 {
meillo@10 291 struct hostent *hent;
meillo@0 292
meillo@10 293 DEBUG(5) debugf("DNS: resolve_byname entered\n");
meillo@0 294
meillo@10 295 if ((hent = gethostbyname(domain))) {
meillo@10 296 char *haddr;
meillo@10 297 int i = 0;
meillo@10 298 while ((haddr = hent->h_addr_list[i++])) {
meillo@10 299 mxip_addr mxip;
meillo@10 300 mxip.ip = *(guint32 *) (haddr);
meillo@10 301 mxip.pref = 0;
meillo@10 302 mxip.name = g_strdup(hent->h_name);
meillo@10 303 list = g_list_append(list, g_memdup(&mxip, sizeof(mxip)));
meillo@10 304 }
meillo@10 305 }
meillo@10 306 return list;
meillo@0 307 }