/*-------------------------------------------------------------------*
 * SyncDet (c) Jason Hamilton                 Created:      01.20.98 *
 *                                            Last updated: 10.20.98 *
 *-------------------------------------------------------------------*
 * This little program scans for any type of
 * DoS that eats up tcp connections, or vhost/clones
 * 
 * Thanks to Patrick Kane for an overflow bug.
 *
 * Syntax: ./syncdet <number-to-find>
 *-------------------------------------------------------------------*
 */

#define LINUX /* undef this if you are running a bsd box like bsd/os.
		The linux machine has several things diff from a a bsd
		machine:

			1) netstat path.
			2) host format has a :port
			3) something else that I can't remember now.

		If you can't get it working, I recommend undefining this
		and try just updating the netstat path. */



#ifdef LINUX
#define NETSTAT_PATH "/bin/netstat"
#else
#define	NETSTAT_PATH "/usr/sbin/netstat"
#endif

#include <netdb.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include <stdlib.h>
#include <netinet/in.h>

#define	SYN_VERSION "v4.4"

void            process_log(), write_all(char *ip),
                add_ip(char *i, char *target), add_domain(char *ip, long num);
long            process_ip(), check_ip(char *ip),
                start_time = 0, clones = 0, totals = 0, res = 0, unr = 0;

struct domains {
	char            domain[25];
	long            high;
	long            low;
	struct domains *nx;
}              *domainhead = NULL;

struct ip_list {
	char            ip[25];	/* full ip */
	char            ip2[25];/* domain */
	char            target[30];
	long            num;
	long            clone;
	long            done;
	struct ip_list *nx;
}              *iphead = NULL;

long            CONN;

main(int argc, char **argv)
{
	struct timeval  timeout;
	char            ptr[300];
	fd_set          fdvar;

	start_time = time(NULL);

	if (argv[1] == NULL) {
		printf("\n\nSyntax: %s <num_con>\n", argv[0]);
		printf("        Where num_con is the number of connections to alert at.\n\n");
		exit(0);
	}
	CONN = atoi(argv[1]);
	snprintf(ptr, sizeof(ptr), "%s -an | grep tcp > netstat.log",
		NETSTAT_PATH);
	system(ptr);
	process_log();
}

long
process_ip()
{
	struct ip_list *c;
	char            s[300], tmp[25];
	long            x = 0, vhost = 0, clone = 0, total = 0;
	c = iphead;

	printf("--- SyncDet %s VHOST/Clone detector (c) Jason Hamilton ---\n\n",
	       SYN_VERSION);

	printf("    Listing c-blocks with greater-than %d connections.\n\n",
		CONN);

	c = iphead;
	while (c != NULL) {
		if (c->num > CONN && c->done == 0) {
			x++;
			printf("--- %11s.* -> %-2d matches ------------\n",
			       c->ip2, c->num);
			write_all(c->ip2);
		}
		c = c->nx;
	}
	printf("\n");
	printf("Total netblocks listed: %d\n", x);
	printf("Total clones found    : %d\n", clones);
	printf("Total resolved users  : %d\n", res);
	printf("Total unresolved users: %d\n", unr);
	printf("Total listed users    : %d\n", totals);

	return x;
}

void
write_all(char *ip)
{
	struct ip_list *c;
	struct domains *d;
	char            addr[5], i_addr[5], *ptr;
	long            toggle = 0, x = 0, high = 0, low = 0;
	struct hostent *h;
	char            s[300];

	d = domainhead;
	while (d) {
		if (strcmp(d->domain, ip) == 0) {
			low = d->low;
			high = d->high;
			break;
		}
		d = d->nx;
	}
	c = iphead;
	while (c) {
		if (strcmp(ip, c->ip2) == 0) {
			c->done = 666;
			sscanf(c->ip, "%d.%d.%d.%d", &addr[0], &addr[1], &addr[2], &addr[3]);
			h = gethostbyaddr(addr, 4, AF_INET);
			if (h == NULL) {
				toggle = 0;
				unr++;
			} else {
				res++;
				toggle = 1;
			}
			totals++;
			if (c->clone > 1) {
				clones += c->clone;
				printf("             x%-4d %s (%s)\n",
				       c->clone, toggle == 0 ? c->ip : h->h_name,
					c->target);
			} else
				printf("                   %s (%s)\n",
				       toggle == 0 ? c->ip : h->h_name, c->target);
		}
		c = c->nx;
	}
}

void
add_domain(char *ip, long numb)
{
	struct domains *n, *c;
	n = (struct domains *) malloc(sizeof(struct domains));
	c = domainhead;

	while (c) {
		if (strcmp(c->domain, ip) == 0) {
			if (numb > c->high)
				c->high = numb;
			if (numb < c->low)
				c->low = numb;
			return;
		}
		c = c->nx;
	}

	if (n) {
		strncpy(n->domain,ip,sizeof(n->domain));
		n->low = 0;
		n->high = 0;
		if (domainhead == NULL) {
			domainhead = n;
		} else {
			c = domainhead;
			while (c->nx != NULL)
				c = c->nx;
			c->nx = n;
		}
	}
}

void
add_ip(char *ip, char *target)
{
	char           *ptr, host[100], host2[100], temp[100];
	struct ip_list *n, *c;
	n = (struct ip_list *) malloc(sizeof(struct ip_list));

	ptr = strtok(ip, ".");
	snprintf(host, sizeof(host), "%s", ptr);
	ptr = strtok(NULL, ".");
	snprintf(temp, sizeof(temp), "%s.%s", host, ptr);
	ptr = strtok(NULL, ".");
	snprintf(host, sizeof(host), "%s.%s", temp, ptr);
	strncpy(host2,host,sizeof(host2));
#ifdef LINUX
        ptr = strtok(NULL, ":");
#else
	ptr = strtok(NULL, ".");
#endif
	add_domain(host2, atoi(ptr));
	snprintf(temp, sizeof(temp), "%s.%s", host, ptr);
	strncpy(host,temp,sizeof(host));
	ptr = strtok(NULL, "");

	if (n != NULL) {
		strncpy(n->ip,host,sizeof(n->ip));
		strncpy(n->ip2,host2,sizeof(n->ip2));
		strncpy(n->target,target,sizeof(n->target));
		n->num = 1;
		n->clone = 1;
		n->done = 0;
		if (iphead == NULL) {
			iphead = n;
		} else {
			c = iphead;
			while (c->nx != NULL)
				c = c->nx;
			c->nx = n;
		}
	}
}

long
check_ip(char *ip)
{
	char           *ptr, host[100], temp[100];
	long            clone_count = 0;
	struct ip_list *c;
	c = iphead;

	ptr = strtok(ip, ".");
	strncpy(host,ptr,sizeof(host));
	ptr = strtok(NULL, ".");
	snprintf(temp, sizeof(temp), "%s.%s", host, ptr);
	ptr = strtok(NULL, ".");
	snprintf(host, sizeof(host), "%s.%s", temp, ptr);
	ptr = strtok(NULL, ".");
	snprintf(temp, sizeof(temp), "%s.%s", host, ptr);
	ptr = strtok(NULL, "");

	while (c != NULL) {
		if (strcmp(c->ip2, host) == 0)
			c->num++;
		if (strcmp(c->ip, temp) == 0) {
			c->clone++;
			clone_count = c->clone;
		}
		c = c->nx;
	}
	return clone_count;
}

void
process_log()
{
	FILE           *fp;
	long            i = 0;
	char            b[1000], *dat, s[300], s2[300], *target,
			*ptr;

	if ((fp = fopen("netstat.log", "r")) == NULL) {
		printf("ERROR: Unable to open \"netstat.log\"\n");
		exit(0);
	}
	while (fgets(b, 1000, fp)) {
		i++;
		dat = strtok(b, " ");
		dat = strtok(NULL, " ");    /* recvq */
		dat = strtok(NULL, " ");    /* sendq */
		target = strtok(NULL, " "); /* local computer's port */
		dat = strtok(NULL, " ");    /* remote machine ip:port */

#ifdef LINUX
		ptr = strtok(dat, ":");
                strncpy(s,ptr,sizeof(s));
                strncpy(s2,ptr,sizeof(s2));
#else
		strncpy(s,dat,sizeof(s));
		strncpy(s2,dat,sizeof(s2));
#endif

		dat = strtok(target, ".");
		dat = strtok(NULL, ".");
		dat = strtok(NULL, ".");

#ifdef LINUX
                dat = strtok(NULL, ":");  /* connected port on local */
#else
                dat = strtok(NULL, ".");  /* connected port on local */
#endif

		target = strtok(NULL, "");  /* connected port on local */
		if (strcmp(s2, "*.*") != 0) {
			if (check_ip(s) < 2)
				add_ip(s2, target);
		}
	}
	if (process_ip() > 0) {
		printf("\nProcessed             : %d connections... \n", i);
		printf("Total time Elapsed    : %d seconds.\n", time(NULL) - start_time);
	}
}
