mx.c #5

  • //
  • guest/
  • bryan_costales/
  • mx.c
  • View
  • Commits
  • Open Download .zip Download (6 KB)
/************************************************************
** $Id: mx.c,v 0.5 2003/12/29 16:45:38 bcx Exp bcx $
**
** Copyright Bryan Costales and Perforce Software, Inc. 2003
**
** This code is "open source" as defined by version 1.9 of
** the Open Source Definition from:
**
**	http://www.opensource.org/docs/definition.php.
**
** Entry points defined in this file:
**
** getmx():
** 	Look up MX records for the passed host, and then
**	look up the IP addresses of each found host.
*************************************************************/

# define EXTERN extern
#include "slow.h"

char **
getmx(char *host, char **list)
{
	char buf[BUFSIZ];
	char *cp;
	HEADER *hp;
	QBUF qbuf;
	int len;
	int acnt, qdcnt;
	u_short pref; 	/* not used */
	u_short type;	/* not used */
	u_long ttl;	/* not used */
	struct hostent *hostp;
	char **p, **pp;
	unsigned char *ep, *up;
	struct in_addr in;
# if HAVE_GETIPNODEBYNAME
	int err;
# endif
	extern int h_errno;

	errno = 0;

	if (host == NULL || *host == '\0')
		return NULL;

	(void)strcpy(buf, host);
	/*
	 * Make sure host ends in a dot to short circuit lookups
	 */
	cp = buf + strlen(buf) - 1;
	if (*cp != '.')
		*(++cp) = '.';
	*(++cp) = '\0';
	/*
	 * Make sure host does not begin with a dot.
	 */
	cp = buf;
	if (*cp == '.')
		++cp;

	/*
	 * The trailing dot above speeds up the lookup.
	 */
	(void)res_init();
	len = res_query(cp, C_IN, T_MX, (u_char *) &qbuf, sizeof(qbuf));
	if (len < 0) 
	{
		(void) fprintf(stderr, "%s: %s(%d): %s: %s\n",
			Prog, __FILE__, __LINE__, 
			cp, hstrerror(h_errno));
		exit(h_errno);
	}

	hp = (HEADER *)&qbuf;
	up = (u_char *)&qbuf + HFIXEDSZ;
	ep = (u_char *)&qbuf + len;

	for (qdcnt = ntohs(hp->qdcount); qdcnt--; up += len + QFIXEDSZ)
	{
		if ((len = dn_skipname(up, ep)) < 0) 
		{
			(void) fprintf(stderr, "%s: %s(%d): %s: %s\n",
				Prog, __FILE__, __LINE__,
				host, hstrerror(h_errno));
			exit(h_errno);
		}
	}

	acnt = ntohs(hp->ancount);
	while (--acnt >= 0 && up < ep)
	{
		if ((len = dn_expand((u_char *)&qbuf, 
			ep, up, (RES_UNC_T) buf, BUFSIZ-1)) < 0)
		{
			break;
		}
		up += len;
		GETSHORT(type, up);
 		up += INT16SZ;
		GETLONG(ttl, up);
		GETSHORT(len, up);
		if (type != T_MX)
		{
			up += len;
			continue;
		}
		GETSHORT(pref, up);
		if ((len = dn_expand((u_char *)&qbuf, 
			ep, up, (RES_UNC_T) buf, BUFSIZ-1)) < 0)
		{
			break;
		}
		up += len;
		if (is_in_list(buf, list) == FALSE)
			list = push_list(buf, list, FALSE);
# if HAVE_GETIPNODEBYNAME
		hostp = getipnodebyname(buf, AF_INET, AI_DEFAULT , &err);
		if (hostp == NULL)
			continue;
		if (hostp->h_aliases == NULL)
		{
			freehostent(hostp);
			continue;
		}
# else
		/*
		 * Okay to fall back to gethostbyname() here
		 * because we are not muti-threading yet.
		 */
		hostp = gethostbyname(buf);
		if (hostp == NULL)
		{
			continue;
		}
		if (hostp->h_addr_list == NULL)
		{
			continue;
		}
# endif
		for (p = hostp->h_addr_list; *p != 0; p++)
		{
			(void) memcpy(&in.s_addr, *p, sizeof (in.s_addr));
			(void) sprintf(buf, "%s", inet_ntoa(in));
			if (is_in_list(buf, list) == FALSE)
				list = push_list(buf, list, FALSE);
			for (pp = hostp->h_aliases; *pp != 0; pp++)
			{
				sprintf(buf, "%s", *pp);
				if (is_in_list(buf, list) == FALSE)
					list = push_list(buf, list, FALSE);
			}
		}
# if HAVE_GETIPNODEBYNAME
		freehostent(hostp);
# endif
	}
	return list;
}

/*
** RBL_LOOKUP -- lookup an IP address at an RBL server
**
*/
int
rbl_lookup(char *server, char *ip, int log)
{
	char buf[BUFSIZ];
	char **iplist;
	int ipcnt;
	char **p;
	struct hostent *hostp;
# if HAVE_GETIPNODEBYNAME
	int err;
# endif
	extern int h_errno;

	errno = 0;

	if (ip == NULL || *ip == '\0')
		return EINVAL;
	if (server == NULL || *server == '\0')
		return EINVAL;

	iplist = mkargv(ip, '.', log);
	if (iplist == NULL)
		return errno;

	ipcnt = 0;
	for (p = iplist; *p != NULL; ++p)
		++ipcnt;
	if (ipcnt < 4)
		return EINVAL;
	sprintf(buf, "%s.%s.%s.%s.%s", iplist[3], iplist[2],
		iplist[1], iplist[0], server);

# if HAVE_GETIPNODEBYNAME
	hostp = getipnodebyname(buf, AF_INET, AI_DEFAULT , &err);
	if (hostp != NULL)
	{
		freehostent(hostp);
		return 0;
	}
	return -(err);
# else
	/*
	 * Okay to fall through to here because we don't
	 * need to access the contents of hostp. We only
	 * care if it is NULL or not. Hence, gethostbyname
	 * is thread-save here.
	 */
	hostp = gethostbyname(buf);
	if (hostp == NULL)
		return -(h_errno);
	return 0;
# endif
}

PRIMARY_KEY *
aliasips(PRIMARY_KEY *list, int *n, PRIMARY_KEY ip)
{
	struct hostent *hp;
	char *host;
	char **p;
	PRIMARY_KEY nip;
# if HAVE_GETIPNODEBYADDR
	int err;
# else
	struct in_addr in;
	char ipbuf[MAXHOSTNAMELEN];
# endif
	if (list == NULL)
	{
		list = try_alloc(__FILE__, __LINE__,
			sizeof(PRIMARY_KEY) * 2, TRUE);
		list[0] = ip;
		list[1] = NULL;
		*n = 1;
	}
	if (AddIPAliases == FALSE)
		return list;
	if (ip == 0)
		return list;

# if HAVE_GETIPNODEBYADDR && HAVE_GETIPNODEBYNAME
	/*
	 * perform IP aliasing here.
	 */
	hp = getipnodebyaddr(&ip, INADDRSZ, AF_INET, &err);
# else
	(void) memcpy(&in.s_addr, ((char *)(&ip)), sizeof(in.s_addr));
	(void) sprintf(ipbuf, "%s", inet_ntoa(in));
	hp = gethostbyaddr(ipbuf, strlen(ipbuf), AF_INET);
# endif
	if (hp == NULL)
		return list;
	if (hp->h_name == NULL)
	{
# if HAVE_GETIPNODEBYADDR && HAVE_GETIPNODEBYNAME
		freehostent(hp);
# endif
		return list;
	}
	host = try_strdup(__FILE__, __LINE__, hp->h_name, TRUE);
# if HAVE_GETIPNODEBYADDR && HAVE_GETIPNODEBYNAME
	freehostent(hp);
	hp = getipnodebyname(host, AF_INET, AI_DEFAULT , &err);
# else
	hp = gethostbyname(host);
# endif
	(void)free(host);
	if (hp == NULL)
		return list;
	if (hp->h_aliases == NULL)
	{
# if HAVE_GETIPNODEBYADDR && HAVE_GETIPNODEBYNAME
		freehostent(hp);
# endif
		return list;
	}
	for (p = hp->h_aliases; *p != NULL; p++)
	{
		nip = inet_network(*p);	
		if ((int)nip == -1)
			continue;
		list = try_realloc(__FILE__, __LINE__, list,
			sizeof(PRIMARY_KEY) * (*n + 2), TRUE);
		list[*n] = nip;
		++(*n);
		list[*n] = NULL;
	}
# if HAVE_GETIPNODEBYADDR && HAVE_GETIPNODEBYNAME
	freehostent(hp);
# endif
	return list;
}
# Change User Description Committed
#5 4222 bryan_costales Massive rewrite to speed up the database writes.
Using a single database now with duplicate keys
where the keys are the IP numbers. Added a purge
command and removed the garbage command. Fixed
some leaking memory bugs and properly closed the
database in a few places were it was not
properly closed. Updated the docs to reflect
this and bumped both the database version and
release number. Running on a FreeBSD 3.x machine
and a Solaris 9 machine.
#4 4052 bryan_costales Implimented:
    whitelisting
    AddMXHost for MX servers that lie
    Converted to thread safe DNS routines
    garbage collection
    RunAsUser and RunAsGroup for root startups
    rebuild the database
    summarize by IP number
Finished all documentation.
Moved release from alpha to beta
#3 3998 bryan_costales Brought the whole distribution up to V0.9
Added a huge abount of documentation.
Added slowedit find
Created startup scripts to launch for testing
Fixed numerous bugs.
Fixed a few portablity issues.
Installed hooks for whitelisting and IP aliases.
#2 3957 bryan_costales Added rbl lookup support and testing for same.
Folded in support for smfi_stop().
Added lots of slowedit commands
Fixed a serious bug in MX lookups.
Added to documentation.
#1 3838 bryan_costales This is pre-release 0.5 (rcs numbering) which includes:
    The milter source files and Makefile
    A regressive testing subdirectory with Makefile and /bin/sh scripts.
    A patches subdirectory with a patch file for V8.13 sendmail
All have been compiled and tested on a 64bit Sun Solaris 9 machine.