view src/lookup.c @ 91:3e7136221104

correct masqmail path in rmail script; remove docs on uninstall on install the correct path to the masqmail executable gets inserted into the rmail script now. now documentation, examples, and the templates are removed on uninstall. Empty directories are the only thing that may remain if one installs masqmail into an unusual path.
author meillo@marmaro.de
date Mon, 21 Jun 2010 09:40:16 +0200
parents f671821d8222
children 116b0269c934
line wrap: on
line source

/* MasqMail Copyright (C) Oliver Kurth,
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>

#include "masqmail.h"

#ifdef RESOLV_TEST
#undef DEBUG
#define DEBUG(x) if(x > 0)
#define debugf g_print
#endif

#ifdef ENABLE_RESOLVER

static union {
	HEADER hdr;
	unsigned char buf[PACKETSZ];
} response;
static unsigned char *resp_end;
static unsigned char *resp_pos;

static int num_answers;
static char name[MAX_DNSNAME];

unsigned short rr_type;
unsigned short rr_dlen;

static unsigned short
getshort(unsigned char *c)
{
	unsigned short u;
	u = c[0];
	return (u << 8) + c[1];
}

static int
dns_resolve(char *domain, int type, gboolean do_search)
{
	int n;
	int i;

	int resp_len;
	/*errno = 0; */

	/*
	   if (!stralloc_copy(&glue,domain)) return DNS_MEM;
	   if (!stralloc_0(&glue)) return DNS_MEM;
	 */

	//  resp_len = res_query(domain, C_IN, type, response.buf, sizeof(response));
	DEBUG(5) debugf("DNS: before res_search()\n");
	if (do_search)
		resp_len = res_search(domain, C_IN, type, response.buf, sizeof(response));
	else
		resp_len = res_query(domain, C_IN, type, response.buf, sizeof(response));
	DEBUG(5) debugf("DBG: after res_search()\n");

	if (resp_len <= 0) {
		/*
		   if (errno == ECONNREFUSED) return DNS_SOFT;
		   if (h_errno == TRY_AGAIN) return DNS_SOFT;
		   return DNS_HARD;
		 */
		return -1;
	}
	if (resp_len >= sizeof(response))
		resp_len = sizeof(response);

	resp_end = response.buf + resp_len;
	resp_pos = response.buf + sizeof(HEADER);
	n = ntohs(response.hdr.qdcount);

	while (n-- > 0) {
		i = dn_expand(response.buf, resp_end, resp_pos, name, MAX_DNSNAME);
		if (i < 0)
			return -1;
		DEBUG(5) debugf("DBG: resolve name = %s\n", name);
		resp_pos += i;
		i = resp_end - resp_pos;
		if (i < QFIXEDSZ)
			return -1;
		resp_pos += QFIXEDSZ;
	}
	num_answers = ntohs(response.hdr.ancount);

	return 0;
}

static int
dns_next()
{
	int i;

	if (num_answers <= 0)
		return 2;
	num_answers--;

	if (resp_pos == resp_end)
		return -1;  /* soft */

	i = dn_expand(response.buf, resp_end, resp_pos, name, 256);
	if (i < 0)
		return -1;  /* soft */
	resp_pos += i;

	i = resp_end - resp_pos;
	if (i < 4 + 3 * 2)
		return -1;  /* soft */

	rr_type = getshort(resp_pos);
	rr_dlen = getshort(resp_pos + 8);
	resp_pos += 10;

	return 0;
}

static int
dns_getip(guint32 * ip)
{
	int ret;

	if ((ret = dns_next()))
		return ret;

	if (rr_type == T_A) {
		if (rr_dlen < 4)
			return -1;  /* soft */
		*ip = *(guint32 *) (resp_pos);
		DEBUG(5) debugf("DNS: dns_getip(): ip = %s\n", inet_ntoa(*(struct in_addr *) ip));
		resp_pos += rr_dlen;

		return 1;
	}
	resp_pos += rr_dlen;
	return 0;
}

static int
dns_getmx(int *pref)
{
	int ret;

	if ((ret = dns_next()))
		return ret;

	if (rr_type == T_MX) {
		if (rr_dlen < 3)
			return -1;  /* soft */

		*pref = (resp_pos[0] << 8) + resp_pos[1];
		if (dn_expand(response.buf, resp_end, resp_pos + 2, name, MAX_DNSNAME) < 0)
			return -1;

		resp_pos += rr_dlen;

		return 1;
	}
	resp_pos += rr_dlen;
	return 0;
}

/*
static int
dns_getname(int type)
{
  int ret;

  if((ret = dns_next())) return ret;

  if (rr_type == type){
    if (dn_expand(response.buf, resp_end, resp_pos, name, MAX_DNSNAME) < 0)
      return -1;

    resp_pos += rr_dlen;

    return 1;
  }
  resp_pos += rr_dlen;
  return 0;
}
*/

static int
dns_look_ip(gchar * domain, guint32 * ip)
{
	gchar *n = domain;

	while (TRUE) {
		if (dns_resolve(n, T_A, FALSE) == 0) {
			dns_next();
			if (rr_type == T_A) {
				if (rr_dlen < 4)
					return -1;  /* soft */
				*ip = *(guint32 *) (resp_pos);

				DEBUG(5) debugf("DNS: dns_look_ip(): ip = %s\n", inet_ntoa(*(struct in_addr *) ip));

				resp_pos += rr_dlen;
				return 0;
			} else if (rr_type == T_CNAME) {
				if (dn_expand(response.buf, resp_end, resp_pos, name, MAX_DNSNAME) < 0)
					return -1;

				DEBUG(5) debugf("DNS: (CNAME) dns_look_ip(): name = %s\n", name);

				resp_pos += rr_dlen;
				n = name;
			} else
				return -1;
		} else
			return -1;
	}
}

GList*
resolve_dns_a(GList * list, gchar * domain)
{
	int ret;

	DEBUG(5) debugf("DNS: resolve_dns_a entered\n");

	if (dns_resolve(domain, T_A, TRUE) == 0) {
		mxip_addr mxip;
		while ((ret = dns_getip(&(mxip.ip))) != 2) {
			if (ret == 1) {
				mxip.name = g_strdup(name);
				mxip.pref = 0;
				list = g_list_append(list, g_memdup(&mxip, sizeof(mxip)));
			}
		}
	}
	return list;
}

static gint
_mx_sort_func(gconstpointer aa, gconstpointer bb)
{
	const mxip_addr *a = (mxip_addr *) aa;
	const mxip_addr *b = (mxip_addr *) bb;

	if (a->pref == b->pref)
		return a->ip - b->ip;
	else
		return a->pref - b->pref;
}

GList*
resolve_dns_mx(GList * list, gchar * domain)
{
	GList *node;
	int ret;
	int cnt = 0;

	DEBUG(5) debugf("DNS: resolve_dns_mx entered\n");

	if (dns_resolve(domain, T_MX, TRUE) == 0) {
		GList *node_next;
		mxip_addr mxip;
		while ((ret = dns_getmx(&(mxip.pref))) != 2) {
			if (ret == 1) {
				mxip.name = g_strdup(name);
				mxip.ip = rand();
				list = g_list_append(list, g_memdup(&mxip, sizeof(mxip)));
				cnt++;
			}
		}

		DEBUG(5) debugf("DNS: found %d mx records\n", cnt);

		/* to randomize sequences with equal pref values,
		   we temporarily 'misused' the ip field and
		   put a random number in it as a secondary sort key.
		 */
		list = g_list_sort(list, _mx_sort_func);

		/* CNAME resolving has to be added as well. */

		for (node = g_list_first(list); node != NULL; node = node_next) {

			mxip_addr *p_mxip = (mxip_addr *) (node->data);
			node_next = g_list_next(node);

			if (dns_look_ip(p_mxip->name, &(p_mxip->ip)) != 0) {
				DEBUG(1) debugf("DNS: could not resolve target of mx %s\n", p_mxip->name);
				list = g_list_remove_link(list, node);
				g_free(node->data);
				g_list_free_1(node);
			}
		}
	}
	return list;
}

#endif

/* now something completely different... */

GList*
resolve_byname(GList * list, gchar * domain)
{
	struct hostent *hent;

	DEBUG(5) debugf("DNS: resolve_byname entered\n");

	if ((hent = gethostbyname(domain))) {
		char *haddr;
		int i = 0;
		while ((haddr = hent->h_addr_list[i++])) {
			mxip_addr mxip;
			mxip.ip = *(guint32 *) (haddr);
			mxip.pref = 0;
			mxip.name = g_strdup(hent->h_name);
			list = g_list_append(list, g_memdup(&mxip, sizeof(mxip)));
		}
	}
	return list;
}

#ifdef RESOLV_TEST
int
main(int argc, char *argv[])
{
	GList *addr_list = NULL, *node;

	g_print("starting res_init()\n");
	g_print("retrans = %d, retry = %d\n", _res.retrans, _res.retry);
	if (res_init() == 0) {
		addr_list = resolve_dns_a(NULL, argv[1]);
		g_print("A:\n");
		foreach(addr_list, node) {
			mxip_addr *p_mxip = (mxip_addr *) (node->data);
			printf("name = %s\n IP = %s\n", p_mxip->name, inet_ntoa(*(struct in_addr *) &(p_mxip->ip)));
		}
		addr_list = resolve_dns_mx(NULL, argv[1]);
		g_print("MX:\n");
		foreach(addr_list, node) {
			mxip_addr *p_mxip = (mxip_addr *) (node->data);
			printf("name = %s\n IP = %s pref = %d\n", p_mxip->name,
			       inet_ntoa(*(struct in_addr *) &(p_mxip->ip)), p_mxip->pref);
		}
		{
			guint32 ip;
			dns_look_ip(argv[1], &ip);
			printf("dns_look_ip: %s\n", inet_ntoa(*((struct in_addr *) (&ip))));
		}
	} else
		printf("res_init() failed.\n");
}
#endif