diff 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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dcclib/ckparse.c	Tue Mar 10 13:49:58 2009 +0100
@@ -0,0 +1,285 @@
+/* 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);
+}