ipsd.c revision 53024
122514Sdarrenr/*
253024Sguido * (C)opyright 1995-1998 Darren Reed.
322514Sdarrenr *
431183Speter * Redistribution and use in source and binary forms are permitted
531183Speter * provided that this notice is preserved and due credit is given
631183Speter * to the original author and the contributors.
722514Sdarrenr *
822514Sdarrenr *   The author of this software makes no garuntee about the
922514Sdarrenr * performance of this package or its suitability to fulfill any purpose.
1022514Sdarrenr *
1122514Sdarrenr */
1222514Sdarrenr#include <stdio.h>
1322514Sdarrenr#include <fcntl.h>
1422514Sdarrenr#include <signal.h>
1522514Sdarrenr#include <stdlib.h>
1622514Sdarrenr#include <netdb.h>
1722514Sdarrenr#include <string.h>
1822514Sdarrenr#include <sys/types.h>
1922514Sdarrenr#include <sys/time.h>
2022514Sdarrenr#include <sys/socket.h>
2122514Sdarrenr#include <netinet/in.h>
2222514Sdarrenr#include <netinet/in_systm.h>
2322514Sdarrenr#include <netinet/ip.h>
2422514Sdarrenr#include <netinet/tcp.h>
2522514Sdarrenr#include <netinet/udp.h>
2622514Sdarrenr#include <netinet/ip_icmp.h>
2722514Sdarrenr#ifndef	linux
2822514Sdarrenr#include <netinet/ip_var.h>
2922514Sdarrenr#include <netinet/tcpip.h>
3022514Sdarrenr#endif
3122514Sdarrenr#include "ip_compat.h"
3222514Sdarrenr#ifdef	linux
3322514Sdarrenr#include <linux/sockios.h>
3422514Sdarrenr#include "tcpip.h"
3522514Sdarrenr#endif
3622514Sdarrenr#include "ipsd.h"
3722514Sdarrenr
3822514Sdarrenr#ifndef	lint
3931183Speterstatic const char sccsid[] = "@(#)ipsd.c	1.3 12/3/95 (C)1995 Darren Reed";
4053024Sguidostatic const char rcsid[] = "@(#)$Id: ipsd.c,v 2.1 1999/08/04 17:30:56 darrenr Exp $";
4122514Sdarrenr#endif
4222514Sdarrenr
4322514Sdarrenrextern	char	*optarg;
4422514Sdarrenrextern	int	optind;
4522514Sdarrenr
4622514Sdarrenr#ifdef	linux
4722514Sdarrenrchar	default_device[] = "eth0";
4822514Sdarrenr#else
4922514Sdarrenr# ifdef	sun
5022514Sdarrenrchar	default_device[] = "le0";
5122514Sdarrenr# else
5222514Sdarrenr#  ifdef	ultrix
5322514Sdarrenrchar	default_device[] = "ln0";
5422514Sdarrenr#  else
5522514Sdarrenrchar	default_device[] = "lan0";
5622514Sdarrenr#  endif
5722514Sdarrenr# endif
5822514Sdarrenr#endif
5922514Sdarrenr
6022514Sdarrenr#define	NPORTS	21
6122514Sdarrenr
6222514Sdarrenru_short	defports[NPORTS] = {
6322514Sdarrenr		  7,   9,  20,  21,  23,  25,  53,  69,  79, 111,
6422514Sdarrenr		123, 161, 162, 512, 513, 514, 515, 520, 540, 6000, 0
6522514Sdarrenr	};
6622514Sdarrenr
6722514Sdarrenripsd_t	*iphits[NPORTS];
6822514Sdarrenrint	writes = 0;
6922514Sdarrenr
7022514Sdarrenr
7122514Sdarrenrint	ipcmp(sh1, sh2)
7222514Sdarrenrsdhit_t	*sh1, *sh2;
7322514Sdarrenr{
7422514Sdarrenr	return sh1->sh_ip.s_addr - sh2->sh_ip.s_addr;
7522514Sdarrenr}
7622514Sdarrenr
7722514Sdarrenr
7822514Sdarrenr/*
7922514Sdarrenr * Check to see if we've already received a packet from this host for this
8022514Sdarrenr * port.
8122514Sdarrenr */
8222514Sdarrenrint	findhit(ihp, src, dport)
8322514Sdarrenripsd_t	*ihp;
8422514Sdarrenrstruct	in_addr	src;
8522514Sdarrenru_short	dport;
8622514Sdarrenr{
8722514Sdarrenr	int	i, j, k;
8822514Sdarrenr	sdhit_t	*sh;
8922514Sdarrenr
9022514Sdarrenr	sh = NULL;
9122514Sdarrenr
9222514Sdarrenr	if (ihp->sd_sz == 4) {
9322514Sdarrenr		for (i = 0, sh = ihp->sd_hit; i < ihp->sd_cnt; i++, sh++)
9422514Sdarrenr			if (src.s_addr == sh->sh_ip.s_addr)
9522514Sdarrenr				return 1;
9622514Sdarrenr	} else {
9722514Sdarrenr		for (i = ihp->sd_cnt / 2, j = (i / 2) - 1; j >= 0; j--) {
9822514Sdarrenr			k = ihp->sd_hit[i].sh_ip.s_addr - src.s_addr;
9922514Sdarrenr			if (!k)
10022514Sdarrenr				return 1;
10122514Sdarrenr			else if (k < 0)
10222514Sdarrenr				i -= j;
10322514Sdarrenr			else
10422514Sdarrenr				i += j;
10522514Sdarrenr		}
10622514Sdarrenr	}
10722514Sdarrenr	return 0;
10822514Sdarrenr}
10922514Sdarrenr
11022514Sdarrenr
11122514Sdarrenr/*
11222514Sdarrenr * Search for port number amongst the sorted array of targets we're
11322514Sdarrenr * interested in.
11422514Sdarrenr */
11522514Sdarrenrint	detect(ip, tcp)
11622514Sdarrenrip_t	*ip;
11722514Sdarrenrtcphdr_t	*tcp;
11822514Sdarrenr{
11922514Sdarrenr	ipsd_t	*ihp;
12022514Sdarrenr	sdhit_t	*sh;
12122514Sdarrenr	int	i, j, k;
12222514Sdarrenr
12322514Sdarrenr	for (i = 10, j = 4; j >= 0; j--) {
12422514Sdarrenr		k = tcp->th_dport - defports[i];
12522514Sdarrenr		if (!k) {
12622514Sdarrenr			ihp = iphits[i];
12722514Sdarrenr			if (findhit(ihp, ip->ip_src, tcp->th_dport))
12822514Sdarrenr				return 0;
12922514Sdarrenr			sh = ihp->sd_hit + ihp->sd_cnt;
13022514Sdarrenr			sh->sh_date = time(NULL);
13122514Sdarrenr			sh->sh_ip.s_addr = ip->ip_src.s_addr;
13222514Sdarrenr			if (++ihp->sd_cnt == ihp->sd_sz)
13322514Sdarrenr			{
13422514Sdarrenr				ihp->sd_sz += 8;
13522514Sdarrenr				sh = realloc(sh, ihp->sd_sz * sizeof(*sh));
13622514Sdarrenr				ihp->sd_hit = sh;
13722514Sdarrenr			}
13822514Sdarrenr			qsort(sh, ihp->sd_cnt, sizeof(*sh), ipcmp);
13922514Sdarrenr			return 0;
14022514Sdarrenr		}
14122514Sdarrenr		if (k < 0)
14222514Sdarrenr			i -= j;
14322514Sdarrenr		else
14422514Sdarrenr			i += j;
14522514Sdarrenr	}
14622514Sdarrenr	return -1;
14722514Sdarrenr}
14822514Sdarrenr
14922514Sdarrenr
15022514Sdarrenr/*
15122514Sdarrenr * Allocate initial storage for hosts
15222514Sdarrenr */
15322514Sdarrenrsetuphits()
15422514Sdarrenr{
15522514Sdarrenr	int	i;
15622514Sdarrenr
15722514Sdarrenr	for (i = 0; i < NPORTS; i++) {
15822514Sdarrenr		if (iphits[i]) {
15922514Sdarrenr			if (iphits[i]->sd_hit)
16022514Sdarrenr				free(iphits[i]->sd_hit);
16122514Sdarrenr			free(iphits[i]);
16222514Sdarrenr		}
16322514Sdarrenr		iphits[i] = (ipsd_t *)malloc(sizeof(ipsd_t));
16422514Sdarrenr		iphits[i]->sd_port = defports[i];
16522514Sdarrenr		iphits[i]->sd_cnt = 0;
16622514Sdarrenr		iphits[i]->sd_sz = 4;
16722514Sdarrenr		iphits[i]->sd_hit = (sdhit_t *)malloc(sizeof(sdhit_t) * 4);
16822514Sdarrenr	}
16922514Sdarrenr}
17022514Sdarrenr
17122514Sdarrenr
17222514Sdarrenr/*
17322514Sdarrenr * cleanup exits
17422514Sdarrenr */
17522514Sdarrenrwaiter()
17622514Sdarrenr{
17722514Sdarrenr	wait(0);
17822514Sdarrenr}
17922514Sdarrenr
18022514Sdarrenr
18122514Sdarrenr/*
18222514Sdarrenr * Write statistics out to a file
18322514Sdarrenr */
18422514Sdarrenrwritestats(nwrites)
18522514Sdarrenrint	nwrites;
18622514Sdarrenr{
18722514Sdarrenr	ipsd_t	**ipsd, *ips;
18822514Sdarrenr	char	fname[32];
18922514Sdarrenr	int	i, fd;
19022514Sdarrenr
19122514Sdarrenr	(void) sprintf(fname, "/var/log/ipsd/ipsd-hits.%d", nwrites);
19222514Sdarrenr	fd = open(fname, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0644);
19322514Sdarrenr	for (i = 0, ipsd = iphits; i < NPORTS; i++, ipsd++) {
19422514Sdarrenr		ips = *ipsd;
19522514Sdarrenr		if (ips->sd_cnt) {
19622514Sdarrenr			write(fd, ips, sizeof(ipsd_t));
19722514Sdarrenr			write(fd, ips->sd_hit, sizeof(sdhit_t) * ips->sd_sz);
19822514Sdarrenr		}
19922514Sdarrenr	}
20022514Sdarrenr	(void) close(fd);
20122514Sdarrenr	exit(0);
20222514Sdarrenr}
20322514Sdarrenr
20422514Sdarrenr
20522514Sdarrenrvoid writenow()
20622514Sdarrenr{
20722514Sdarrenr	signal(SIGCHLD, waiter);
20822514Sdarrenr	switch (fork())
20922514Sdarrenr	{
21022514Sdarrenr	case 0 :
21122514Sdarrenr		writestats(writes);
21222514Sdarrenr		exit(0);
21322514Sdarrenr	case -1 :
21422514Sdarrenr		perror("vfork");
21522514Sdarrenr		break;
21622514Sdarrenr	default :
21722514Sdarrenr		writes++;
21822514Sdarrenr		setuphits();
21922514Sdarrenr		break;
22022514Sdarrenr	}
22122514Sdarrenr}
22222514Sdarrenr
22322514Sdarrenr
22422514Sdarrenrvoid	usage(prog)
22522514Sdarrenrchar	*prog;
22622514Sdarrenr{
22722514Sdarrenr	fprintf(stderr, "Usage: %s [-d device]\n", prog);
22822514Sdarrenr	exit(1);
22922514Sdarrenr}
23022514Sdarrenr
23122514Sdarrenr
23222514Sdarrenrvoid detecthits(fd, writecount)
23322514Sdarrenrint fd, writecount;
23422514Sdarrenr{
23522514Sdarrenr	struct	in_addr	ip;
23622514Sdarrenr	int	hits = 0;
23722514Sdarrenr
23822514Sdarrenr	while (1) {
23922514Sdarrenr		hits += readloop(fd, ip);
24022514Sdarrenr		if (hits > writecount) {
24122514Sdarrenr			writenow();
24222514Sdarrenr			hits = 0;
24322514Sdarrenr		}
24422514Sdarrenr	}
24522514Sdarrenr}
24622514Sdarrenr
24722514Sdarrenr
24822514Sdarrenrmain(argc, argv)
24922514Sdarrenrint	argc;
25022514Sdarrenrchar	*argv[];
25122514Sdarrenr{
25231183Speter	char	*name =  argv[0], *dev = NULL;
25331183Speter	int	fd, writeafter = 10000, angelic = 0, c;
25422514Sdarrenr
25522514Sdarrenr	while ((c = getopt(argc, argv, "ad:n:")) != -1)
25622514Sdarrenr		switch (c)
25722514Sdarrenr		{
25822514Sdarrenr		case 'a' :
25922514Sdarrenr			angelic = 1;
26022514Sdarrenr			break;
26122514Sdarrenr		case 'd' :
26222514Sdarrenr			dev = optarg;
26322514Sdarrenr			break;
26422514Sdarrenr		case 'n' :
26522514Sdarrenr			writeafter = atoi(optarg);
26622514Sdarrenr			break;
26722514Sdarrenr		default :
26822514Sdarrenr			fprintf(stderr, "Unknown option \"%c\"\n", c);
26922514Sdarrenr			usage(name);
27022514Sdarrenr		}
27122514Sdarrenr
27222514Sdarrenr	bzero(iphits, sizeof(iphits));
27322514Sdarrenr	setuphits();
27422514Sdarrenr
27522514Sdarrenr	if (!dev)
27622514Sdarrenr		dev = default_device;
27722514Sdarrenr	printf("Device:  %s\n", dev);
27822514Sdarrenr	fd = initdevice(dev, 60);
27922514Sdarrenr
28022514Sdarrenr	if (!angelic) {
28122514Sdarrenr		switch (fork())
28222514Sdarrenr		{
28322514Sdarrenr		case 0 :
28422514Sdarrenr			(void) close(0);
28522514Sdarrenr			(void) close(1);
28622514Sdarrenr			(void) close(2);
28722514Sdarrenr			(void) setpgrp(0, getpgrp());
28822514Sdarrenr			(void) setsid();
28922514Sdarrenr			break;
29022514Sdarrenr		case -1:
29122514Sdarrenr			perror("fork");
29222514Sdarrenr			exit(-1);
29322514Sdarrenr		default:
29422514Sdarrenr			exit(0);
29522514Sdarrenr		}
29622514Sdarrenr	}
29722514Sdarrenr	signal(SIGUSR1, writenow);
29822514Sdarrenr	detecthits(fd, writeafter);
29922514Sdarrenr}
300