view dccd/dump-clients/dump-clients.c @ 5:0a7a5940ee3a

Change description per license
author Peter Gervai <grin@grin.hu>
date Tue, 10 Mar 2009 15:03:24 +0100
parents c7f6b056b673
children
line wrap: on
line source

/* Distributed Checksum Clearinghouse
 *
 * dump list of dccd clients
 *
 * 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.20 $Revision$
 */

#include "dccd_defs.h"

static const char *homedir;

u_char grey_on;
static u_char nonames, quiet, avg;


static void NRATTRIB
usage(void)
{
	fprintf(stderr, "usage: [-anqg] [-h homedir] [ifile1 ifile2 ...]\n");
	exit(1);
}



static void PATTRIB(1,2)
error_msg(const char *p, ...)
{
	va_list args;

	fflush(stdout);

	va_start(args, p);
	vfprintf(stderr, p, args);
	va_end(args);
	putchar('\n');
}



static u_char
clients_read(const char *fname, FILE *f, off_t pos, void *buf, int buf_len)
{
	int i;

	if (fseeko(f, pos, 0)) {
		error_msg("fseeko(%s,%d): %s", fname, (int)pos, ERROR_STR());
		fclose(f);
		return 0;
	}

	i = fread(buf, buf_len, 1, f);
	if (i == 1)
		return 1;

	if (feof(f))
		return 0;

	error_msg("fread(%s): %s", fname, ERROR_STR());
	fclose(f);
	return 0;
}



static void
dump_file(const char *fname0)
{
#	define PAT_REQUESTS	L_DWPAT(7)" "L_DWPAT(6)" "
#	define PAT_REQUESTS_B   "%7s %6s "
#	define PAT_AVGS		"%7d %6d %4.1f "
#	define PAT_AVGS_B	"   %14s   "
#	define PAT_DATE_ID	"%-14s %6d%c"
#	define PAT_DATE_ID_B	"%-14s %6s "
#	define PAT_VERS		"%1d "
#	define PAT_VERS_B	"%1s "
#	define PAT_DELAY	"%5.3f "
#	define PAT_DELAY_B	"%5s "
	DCC_PATH fname;
	FILE *f;
	struct stat sb;
	CLIENTS_HEADER header;
	RL_DATA data;
	struct {
	    u_int   hosts;
	    u_int   requests;
	    u_int   nops;
	}  versions[DCC_PKT_VERSION_MAX+1];
	time_t secs;
	struct tm tm;
	char date_buf[40];
	char date_buf2[40];
	int inflate;
	double delay_us;
	DCC_SOCKU su;
	char name[DCC_MAXDOMAINLEN];
	char sustr[DCC_SU2STR_SIZE];
	off_t pos;
	int total, active, i;

	if (!fnm2abs(fname, fname0, 0)) {
		error_msg("name \"%s\" too long", fname0);
		exit(1);
	}

	printf("%s\n", fname);

	f = fopen(fname, "r");
	if (!f) {
		error_msg("stat(%s): %s",
			  fname, ERROR_STR());
		exit(1);
	}
	if (0 > fstat(fileno(f), &sb)) {
		error_msg("stat(%s): %s", fname, ERROR_STR());
		exit(1);
	}
	pos = sb.st_size;
	if (pos < ISZ(header)
	    || ((pos - ISZ(header)) % ISZ(RL_DATA)) != 0) {
		error_msg("%s has invalid size %d", fname, (int)pos);
		exit(1);
	}

	if (!clients_read(fname, f, 0, &header, sizeof(header)))
		exit(1);
	if (strcmp(header.magic, CLIENTS_MAGIC(0))
	    && strcmp(header.magic, CLIENTS_MAGIC(1))) {
		error_msg("unrecognized magic in %s", fname);
		exit(1);
	}
	if (header.hash_len > RL_MIN_MAX_MAX) {
		error_msg("unrecognized hash_len=%d in %s",
			  header.hash_len, fname);
		exit(1);
	}
	strftime(date_buf, sizeof(date_buf), "%m/%d %X",
		 gmtime_r(&header.now, &tm));
	strftime(date_buf2, sizeof(date_buf2), "%m/%d %X",
		 gmtime_r(&header.cleared, &tm));
	printf("recorded %s  cleared %s  anon delay=", date_buf, date_buf2);
	if (header.anon_delay_us == DCC_ANON_DELAY_FOREVER) {
		printf("forever");
	} else {
		printf("%d", header.anon_delay_us/1000);
		if (header.anon_delay_inflate != DCC_ANON_INFLATE_OFF)
			printf(",%d", header.anon_delay_inflate);
	}
	putchar('\n');

	if (avg)
		printf(PAT_REQUESTS_B
		       PAT_AVGS_B
		       PAT_DATE_ID_B
		       PAT_VERS_B
		       PAT_DELAY_B "\n",
		       "ops", "nops",
		       "averages",
		       "  last seen", "ID",
		       "V",
		       "delay");
	else
		printf(PAT_REQUESTS_B
		       PAT_DATE_ID_B
		       PAT_VERS_B
		       PAT_DELAY_B "\n",
		       "ops", "nops",
		       "  last seen", "ID",
		       "V",
		       "delay");

	total = 0;
	active = 0;
	memset(versions, 0, sizeof(versions));
	while ((pos -= ISZ(RL_DATA)) >= ISZ(header)) {
		if (!clients_read(fname, f, pos, &data, sizeof(data)))
			break;

		++total;
		if (data.requests)
			++active;

		if (data.pkt_vers < DIM(versions))
			i = data.pkt_vers;
		else
			i = 0;
		++versions[i].hosts;
		versions[i].requests += data.requests;
		versions[i].nops += data.nops;

		if (quiet)
			continue;

		if (data.requests != 0 || data.nops != 0) {
			printf(PAT_REQUESTS,
			       data.requests, data.nops);
		} else {
			printf(PAT_REQUESTS_B, "-", "-");
		}

		if (avg) {
			if (data.requests_avg != 0 || data.nops_avg != 0) {
				secs = header.now - data.requests_avg_start;
				printf(PAT_AVGS,
				       data.requests_avg, data.nops_avg,
				       secs / (60*60*1.0));
			} else {
				printf(PAT_AVGS_B, "");
			}
		}

		strftime(date_buf, sizeof(date_buf), "%m/%d %X",
			 gmtime_r(&data.last_used, &tm));
		if (data.clnt_id == DCC_ID_ANON)
			printf(PAT_DATE_ID_B, date_buf, "");
		else if (data.clnt_id == DCC_ID_SRVR_ROGUE)
			printf(PAT_DATE_ID_B, date_buf, "server");
		else
			printf(PAT_DATE_ID, date_buf, data.clnt_id,
			       (data.flags & RL_FG_ANON) ? '*' : ' ');

		if (data.pkt_vers != 0)
			printf(PAT_VERS, data.pkt_vers);
		else if (data.clnt_id == DCC_ID_SRVR_ROGUE)
			printf(PAT_VERS_B, "");
		else
			printf(PAT_VERS_B, "?");

		if (data.flags & RL_FG_PASSWD) {
			printf(PAT_DELAY_B, "pass");
		} else if (data.flags & RL_FG_UKN_ID) {
			printf(PAT_DELAY_B, "ID");
		} else if (data.flags & RL_FG_BL_ADDR) {
			printf(PAT_DELAY_B, "A BL");
		} else if (data.flags & RL_FG_BL_ID) {
			printf(PAT_DELAY_B, "ID BL");
		} else if (data.flags & RL_FG_BL_BAD) {
			printf(PAT_DELAY_B, "BAD");
		} else if ((data.flags & RL_FG_ANON)
			   && header.anon_delay_inflate != 0) {
			inflate = 1 + (RL_REQUESTS_AVG(&data)
				       / header.anon_delay_inflate);
			if (inflate > (DCC_ANON_DELAY_MAX
				       / header.anon_delay_us)) {
				delay_us = DCC_ANON_DELAY_MAX;
			} else {
				delay_us = inflate*header.anon_delay_us;
			}
			printf(PAT_DELAY, delay_us/DCC_US);
		} else {
			printf(PAT_DELAY_B, "");
		}

		dcc_mk_su(&su, AF_INET6, &data.clnt_addr, 0);
		if (nonames) {
			printf("%s\n",
			       dcc_su2str2(sustr, sizeof(sustr), &su));
		} else {
			printf("%-16s %s\n",
			       dcc_su2str2(sustr, sizeof(sustr), &su),
			       dcc_su2name(name, sizeof(name), &su));
		}
	}

	fclose(f);

	printf("%d of %d records active\n\n", active, total);

	printf("version  hosts requests     nops\n");
	for (i = 0; i < DIM(versions); ++i) {
		if (versions[i].hosts == 0)
			continue;
		printf("%6d %6d %8d %8d\n",
		       i, versions[i].hosts,
		       versions[i].requests, versions[i].nops);
	}

	printf("\n       *  anonymous\n");
	printf("    pass  bad password\n");
	printf("      ID  unknown ID\n");
	printf("    A BL  address blacklist\n");
	printf("   ID BL  ID blacklist\n");
	printf("     BAD  otherwise bad\n");
}



int NRATTRIB
main(int argc, char **argv)
{
	int i;

	avg = 0;
	nonames = 0;
	quiet = 0;

	while ((i = getopt(argc, argv, "anqgh:")) != -1) {
		switch (i) {
		case 'a':
			++avg;
			break;

		case 'n':
			nonames = 1;
			break;

		case 'q':
			quiet = 1;
			break;

		case 'g':
			grey_on = 1;
			break;

		case 'h':
			homedir = optarg;
			break;

		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;

	dcc_cdhome(0, homedir, 1);

	if (argc == 0) {
		dump_file(CLIENTS_NM());
	} else {
		for (i = 0; i < argc; ++i) {
			dump_file(argv[i]);
		}
	}

	exit(0);
}