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