ipsd.c revision 80486
1/*
2 * (C)opyright 1995-1998 Darren Reed.
3 *
4 * See the IPFILTER.LICENCE file for details on licencing.
5 *
6 *   The author of this software makes no garuntee about the
7 * performance of this package or its suitability to fulfill any purpose.
8 *
9 */
10#include <stdio.h>
11#include <fcntl.h>
12#include <signal.h>
13#include <stdlib.h>
14#include <netdb.h>
15#include <string.h>
16#include <sys/types.h>
17#include <sys/time.h>
18#include <sys/socket.h>
19#include <netinet/in.h>
20#include <netinet/in_systm.h>
21#include <netinet/ip.h>
22#include <netinet/tcp.h>
23#include <netinet/udp.h>
24#include <netinet/ip_icmp.h>
25#ifndef	linux
26#include <netinet/ip_var.h>
27#include <netinet/tcpip.h>
28#endif
29#include "ip_compat.h"
30#ifdef	linux
31#include <linux/sockios.h>
32#include "tcpip.h"
33#endif
34#include "ipsd.h"
35
36#ifndef	lint
37static const char sccsid[] = "@(#)ipsd.c	1.3 12/3/95 (C)1995 Darren Reed";
38static const char rcsid[] = "@(#)$Id: ipsd.c,v 2.1.4.1 2001/06/26 10:43:21 darrenr Exp $";
39#endif
40
41extern	char	*optarg;
42extern	int	optind;
43
44#ifdef	linux
45char	default_device[] = "eth0";
46#else
47# ifdef	sun
48char	default_device[] = "le0";
49# else
50#  ifdef	ultrix
51char	default_device[] = "ln0";
52#  else
53char	default_device[] = "lan0";
54#  endif
55# endif
56#endif
57
58#define	NPORTS	21
59
60u_short	defports[NPORTS] = {
61		  7,   9,  20,  21,  23,  25,  53,  69,  79, 111,
62		123, 161, 162, 512, 513, 514, 515, 520, 540, 6000, 0
63	};
64
65ipsd_t	*iphits[NPORTS];
66int	writes = 0;
67
68
69int	ipcmp(sh1, sh2)
70sdhit_t	*sh1, *sh2;
71{
72	return sh1->sh_ip.s_addr - sh2->sh_ip.s_addr;
73}
74
75
76/*
77 * Check to see if we've already received a packet from this host for this
78 * port.
79 */
80int	findhit(ihp, src, dport)
81ipsd_t	*ihp;
82struct	in_addr	src;
83u_short	dport;
84{
85	int	i, j, k;
86	sdhit_t	*sh;
87
88	sh = NULL;
89
90	if (ihp->sd_sz == 4) {
91		for (i = 0, sh = ihp->sd_hit; i < ihp->sd_cnt; i++, sh++)
92			if (src.s_addr == sh->sh_ip.s_addr)
93				return 1;
94	} else {
95		for (i = ihp->sd_cnt / 2, j = (i / 2) - 1; j >= 0; j--) {
96			k = ihp->sd_hit[i].sh_ip.s_addr - src.s_addr;
97			if (!k)
98				return 1;
99			else if (k < 0)
100				i -= j;
101			else
102				i += j;
103		}
104	}
105	return 0;
106}
107
108
109/*
110 * Search for port number amongst the sorted array of targets we're
111 * interested in.
112 */
113int	detect(ip, tcp)
114ip_t	*ip;
115tcphdr_t	*tcp;
116{
117	ipsd_t	*ihp;
118	sdhit_t	*sh;
119	int	i, j, k;
120
121	for (i = 10, j = 4; j >= 0; j--) {
122		k = tcp->th_dport - defports[i];
123		if (!k) {
124			ihp = iphits[i];
125			if (findhit(ihp, ip->ip_src, tcp->th_dport))
126				return 0;
127			sh = ihp->sd_hit + ihp->sd_cnt;
128			sh->sh_date = time(NULL);
129			sh->sh_ip.s_addr = ip->ip_src.s_addr;
130			if (++ihp->sd_cnt == ihp->sd_sz)
131			{
132				ihp->sd_sz += 8;
133				sh = realloc(sh, ihp->sd_sz * sizeof(*sh));
134				ihp->sd_hit = sh;
135			}
136			qsort(sh, ihp->sd_cnt, sizeof(*sh), ipcmp);
137			return 0;
138		}
139		if (k < 0)
140			i -= j;
141		else
142			i += j;
143	}
144	return -1;
145}
146
147
148/*
149 * Allocate initial storage for hosts
150 */
151setuphits()
152{
153	int	i;
154
155	for (i = 0; i < NPORTS; i++) {
156		if (iphits[i]) {
157			if (iphits[i]->sd_hit)
158				free(iphits[i]->sd_hit);
159			free(iphits[i]);
160		}
161		iphits[i] = (ipsd_t *)malloc(sizeof(ipsd_t));
162		iphits[i]->sd_port = defports[i];
163		iphits[i]->sd_cnt = 0;
164		iphits[i]->sd_sz = 4;
165		iphits[i]->sd_hit = (sdhit_t *)malloc(sizeof(sdhit_t) * 4);
166	}
167}
168
169
170/*
171 * cleanup exits
172 */
173waiter()
174{
175	wait(0);
176}
177
178
179/*
180 * Write statistics out to a file
181 */
182writestats(nwrites)
183int	nwrites;
184{
185	ipsd_t	**ipsd, *ips;
186	char	fname[32];
187	int	i, fd;
188
189	(void) sprintf(fname, "/var/log/ipsd/ipsd-hits.%d", nwrites);
190	fd = open(fname, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0644);
191	for (i = 0, ipsd = iphits; i < NPORTS; i++, ipsd++) {
192		ips = *ipsd;
193		if (ips->sd_cnt) {
194			write(fd, ips, sizeof(ipsd_t));
195			write(fd, ips->sd_hit, sizeof(sdhit_t) * ips->sd_sz);
196		}
197	}
198	(void) close(fd);
199	exit(0);
200}
201
202
203void writenow()
204{
205	signal(SIGCHLD, waiter);
206	switch (fork())
207	{
208	case 0 :
209		writestats(writes);
210		exit(0);
211	case -1 :
212		perror("vfork");
213		break;
214	default :
215		writes++;
216		setuphits();
217		break;
218	}
219}
220
221
222void	usage(prog)
223char	*prog;
224{
225	fprintf(stderr, "Usage: %s [-d device]\n", prog);
226	exit(1);
227}
228
229
230void detecthits(fd, writecount)
231int fd, writecount;
232{
233	struct	in_addr	ip;
234	int	hits = 0;
235
236	while (1) {
237		hits += readloop(fd, ip);
238		if (hits > writecount) {
239			writenow();
240			hits = 0;
241		}
242	}
243}
244
245
246main(argc, argv)
247int	argc;
248char	*argv[];
249{
250	char	*name =  argv[0], *dev = NULL;
251	int	fd, writeafter = 10000, angelic = 0, c;
252
253	while ((c = getopt(argc, argv, "ad:n:")) != -1)
254		switch (c)
255		{
256		case 'a' :
257			angelic = 1;
258			break;
259		case 'd' :
260			dev = optarg;
261			break;
262		case 'n' :
263			writeafter = atoi(optarg);
264			break;
265		default :
266			fprintf(stderr, "Unknown option \"%c\"\n", c);
267			usage(name);
268		}
269
270	bzero(iphits, sizeof(iphits));
271	setuphits();
272
273	if (!dev)
274		dev = default_device;
275	printf("Device:  %s\n", dev);
276	fd = initdevice(dev, 60);
277
278	if (!angelic) {
279		switch (fork())
280		{
281		case 0 :
282			(void) close(0);
283			(void) close(1);
284			(void) close(2);
285			(void) setpgrp(0, getpgrp());
286			(void) setsid();
287			break;
288		case -1:
289			perror("fork");
290			exit(-1);
291		default:
292			exit(0);
293		}
294	}
295	signal(SIGUSR1, writenow);
296	detecthits(fd, writeafter);
297}
298