view dcclib/ckparse.c @ 0:c7f6b056b673

First import of vendor version
author Peter Gervai <grin@grin.hu>
date Tue, 10 Mar 2009 13:49:58 +0100
parents
children
line wrap: on
line source

/* Distributed Checksum Clearinghouse
 *
 * parse a named checksum
 *
 * Copyright (c) 2008 by Rhyolite Software, LLC
 *
 * This agreement is not applicable to any entity which sells anti-spam
 * solutions to others or provides an anti-spam solution as part of a
 * security solution sold to other entities, or to a private network
 * which employs the DCC or uses data provided by operation of the DCC
 * but does not provide corresponding data to other users.
 *
 * Permission to use, copy, modify, and distribute this software without
 * changes for any purpose with or without fee is hereby granted, provided
 * that the above copyright notice and this permission notice appear in all
 * copies and any distributed versions or copies are either unchanged
 * or not called anything similar to "DCC" or "Distributed Checksum
 * Clearinghouse".
 *
 * Parties not eligible to receive a license under this agreement can
 * obtain a commercial license to use DCC by contacting Rhyolite Software
 * at sales@rhyolite.com.
 *
 * A commercial license would be for Distributed Checksum and Reputation
 * Clearinghouse software.  That software includes additional features.  This
 * free license for Distributed ChecksumClearinghouse Software does not in any
 * way grant permision to use Distributed Checksum and Reputation Clearinghouse
 * software
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE, LLC DISCLAIMS ALL
 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE, LLC
 * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 *
 * Rhyolite Software DCC 1.3.103-1.67 $Revision$
 */

#include "dcc_ck.h"
#include "dcc_xhdr.h"
#ifndef DCC_WIN32
#include <arpa/inet.h>
#endif

#define MAX_SERVER_CIDR_BITS 16		/* fix dcc.8 if this changes */


static int				/* -1=fatal 0=problem */
dcc_host2ck(DCC_EMSG emsg, DCC_WF *wf,
	    const char *ck,		/* this string of an IP address */
	    DCC_TGTS tgts,		/* # of targets */
	    DCC_PARSED_CK_FNC fnc,	/* do something with each checksum */
	    DCC_PARSED_CK_CIDR_FNC cidr_fnc)
{
	int error;
	DCC_FNM_LNO_BUF fnm_buf;
	struct in6_addr addr6, mask6, *addr6p;
	DCC_SUM sum;
	DCC_SOCKU *sup;
	int i, j, bits;

	/* recognize xxx.xxx.xxx.xxx/y for IP address blocks
	 * as well as simple IP addresses */
	bits = dcc_str2cidr(emsg, &addr6, &mask6, 0, ck,
			    wf_fnm(wf, wf->fno), wf->lno);
	if (bits < 0)
		return 0;

	if (bits > 0) {
		/* use client CIDR blocks if possible */
		if (cidr_fnc)
			return cidr_fnc(emsg, wf, bits, &addr6, &mask6, tgts);

		/* This is for a server whitelist, because client whitelists
		 * come here with non-null cidr_fnc
		 * Allow only class-B sized blocks, because server whitelist
		 * entries for a CIDR block consist of one checksum per IP
		 * address in the CIDR block.  A line in a whitelist file
		 * specifying a class-B block requires the addition of 65,536
		 * checksums to the server database.  Instead, use whiteclnt
		 * entries. */
		if (128-bits > MAX_SERVER_CIDR_BITS) {
			dcc_pemsg(EX_NOHOST, emsg,
				  "CIDR block length in %s too large%s",
				  ck, wf_fnm_lno(&fnm_buf, wf));
			return 0;
		}

		for (i = 1 << (128-bits); i > 0; --i) {
			dcc_ck_ipv6(sum, &addr6);
			j = fnc(emsg, wf, DCC_CK_IP, sum, tgts);
			if (j <= 0)
				return j;
			addr6.s6_addr32[3] = ntohl(addr6.s6_addr32[3]);
			++addr6.s6_addr32[3];
			addr6.s6_addr32[3] = htonl(addr6.s6_addr32[3]);
		}
		return 1;
	}

	/* we appear to have a host name,
	 * which is not allowed in a per-user whitelist */
	if (wf->wf_flags & DCC_WF_PER_USER) {
		dcc_pemsg(EX_NOHOST, emsg,
			  "hostname checksum illegal in per-user whitelist%s",
			  wf_fnm_lno(&fnm_buf, wf));
		return 0;
	}

	if (wf->wtbl)			/* need future host name resolutions */
		wf->wtbl->hdr.flags |= DCC_WHITE_FG_HOSTNAMES;

	memset(&addr6, 0, sizeof(addr6));
	dcc_host_lock();
	/* don't use SOCKS host name resolution because the host names that
	 * most need whitelisting are inside the SOCKS firewall and may not
	 * be known to outside DNS servers. */
	if (!dcc_get_host(ck, 2, &error)) {
		dcc_pemsg(EX_NOHOST, emsg,
			  "hostname \"%s\": %s%s",
			  ck, DCC_HSTRERROR(error),
			  wf_fnm_lno(&fnm_buf, wf));
		dcc_host_unlock();
		return 0;
	}

	for (sup = dcc_hostaddrs; sup < dcc_hostaddrs_end; ++sup) {
		if (sup->sa.sa_family == AF_INET6) {
			addr6p = &sup->ipv6.sin6_addr;
		} else {
			dcc_ipv4toipv6(&addr6, sup->ipv4.sin_addr);
			addr6p = &addr6;
		}
		if (cidr_fnc) {
			bits = 128;
			dcc_bits2mask(&mask6, bits);
			j = cidr_fnc(emsg, wf, bits, addr6p, &mask6, tgts);
		} else {
			dcc_ck_ipv6(sum, addr6p);
			j = fnc(emsg, wf, DCC_CK_IP, sum, tgts);
		}
		if (j <= 0) {
			dcc_host_unlock();
			return j;
		}
	}
	dcc_host_unlock();
	return 1;
}



/* generate checksum value from the name of the checksum and a string */
int					/* 1=ok 0=problem -1=fatal */
dcc_parse_ck(DCC_EMSG emsg,		/* failure message here */
	     DCC_WF *wf,
	     const char *type_nm,
	     DCC_CK_TYPES type,
	     const char *str,		/* ASCII string to generate checksum */
	     DCC_TGTS tgts,		/* # of targets */
	     DCC_PARSED_CK_FNC add_fnc,	/* do something with the checksum */
	     DCC_PARSED_CK_CIDR_FNC cidr_fnc)
{
	DCC_FNM_LNO_BUF fnm_buf;
	char *phdr, c, hdr_buf[80];
	DCC_SUM sum;
	const char *pstr;

	/* compute the checksum */
	switch (type) {
	case DCC_CK_IP:
		return dcc_host2ck(emsg, wf, str, tgts, add_fnc, cidr_fnc);

	case DCC_CK_ENV_FROM:
	case DCC_CK_FROM:
	case DCC_CK_MESSAGE_ID:
	case DCC_CK_RECEIVED:
	case DCC_CK_ENV_TO:
		dcc_str2ck(sum, 0, 0, str);
		return add_fnc(emsg, wf, type, sum, tgts);

	case DCC_CK_SUB:
		str += strspn(str, DCC_WHITESPACE);
		pstr = str;
		phdr = hdr_buf;
		for (;;) {
			c = *pstr++;
			if (c == '\0' || c == ':'
			    || DCC_IS_WHITE(c))
				break;
			c = DCC_TO_LOWER(c);
			*phdr++ = c;
			if (phdr >= &hdr_buf[sizeof(hdr_buf)]) {
				dcc_pemsg(EX_DATAERR, emsg,
					  " imposible substitute header name"
					  " in \"%s\"%s",
					  str, wf_fnm_lno(&fnm_buf, wf));
				return 0;
			}
		}
		pstr += strspn(pstr, DCC_WHITESPACE);
		if (*pstr == '\0' || phdr == hdr_buf) {
			dcc_pemsg(EX_DATAERR, emsg,
				  " substitute header name absent in \"%s\"%s",
				  str, wf_fnm_lno(&fnm_buf, wf));
			return 0;
		}
		dcc_str2ck(sum, hdr_buf, phdr-hdr_buf, pstr);
		return add_fnc(emsg, wf, type, sum, tgts);

	case DCC_CK_INVALID:
	case DCC_CK_BODY:
	case DCC_CK_FUZ1:
	case DCC_CK_FUZ2:
	case DCC_CK_G_MSG_R_TOTAL:
	case DCC_CK_G_TRIPLE_R_BULK:
	case DCC_CK_SRVR_ID:
		break;
	}

	dcc_pemsg(EX_DATAERR, emsg, "unrecognized checksum type \"%s\"%s",
		  type_nm, wf_fnm_lno(&fnm_buf, wf));
	return 0;
}



/* generate checksum value from the name of the checksum and hex values */
int					/* 1=ok 0=syntax -1=fatal */
dcc_parse_hex_ck(DCC_EMSG emsg,		/* failure message here */
		 DCC_WF *wf,
		 const char *type_nm,
		 DCC_CK_TYPES type,
		 const char *str,	/* ASCII string to generate checksum */
		 DCC_TGTS tgts,		/* # of targets */
		 DCC_PARSED_CK_FNC add_fnc) /* do something with the checksum */
{
	union {
	    u_int32_t n[4];
	    DCC_SUM sum;
	} u;
	DCC_FNM_LNO_BUF fnm_buf;
	int id;

	if (type == DCC_CK_INVALID) {
		dcc_pemsg(EX_DATAERR, emsg,
			  "unrecognized checksum type \"%s\"%s",
			  type_nm, wf_fnm_lno(&fnm_buf, wf));
		return 0;
	}

	if (4 == sscanf(str, DCC_CKSUM_HEX_PAT"\n",
			&u.n[0], &u.n[1], &u.n[2], &u.n[3])
	    || (type == DCC_CK_SUB
		&& 4 == sscanf(str, "%*s "DCC_CKSUM_HEX_PAT"\n",
			       &u.n[0], &u.n[1], &u.n[2], &u.n[3]))) {
		/* recognize simple hex checksums */
		u.n[0] = htonl(u.n[0]);
		u.n[1] = htonl(u.n[1]);
		u.n[2] = htonl(u.n[2]);
		u.n[3] = htonl(u.n[3]);

	} else if (1 == sscanf(str, DCC_XHDR_ID_SIMPLE" at %d", &id)
		   || 1 == sscanf(str, DCC_XHDR_ID_REP_OK" at %d", &id)
		   || 1 == sscanf(str, DCC_XHDR_ID_IGNORE" at %d", &id)
		   || 1 == sscanf(str, DCC_XHDR_ID_ROGUE" at %d", &id)) {
		/* parse server-ID declarations */
		memset(&u, 0, sizeof(u));
		u.sum[0] = DCC_CK_SRVR_ID;
		u.sum[1] = id >> 8;
		u.sum[2] = id;

	} else {
		dcc_pemsg(EX_DATAERR, emsg,
			  "unrecognized checksum value \"%s\"%s",
			  str, wf_fnm_lno(&fnm_buf, wf));
		return 0;
	}

	/* apply the function to the checksum */
	return add_fnc(emsg, wf, type, u.sum, tgts);
}