ipsd.c revision 22514
1223637Sbz/*
2126258Smlaier * (C)opyright December 1995 Darren Reed.
3126258Smlaier *
4126258Smlaier *   This software may be freely distributed as long as it is not altered
5223637Sbz * in any way and that this messagge always accompanies it.
6126258Smlaier *
7126258Smlaier *   The author of this software makes no garuntee about the
8126258Smlaier * performance of this package or its suitability to fulfill any purpose.
9126258Smlaier *
10126258Smlaier */
11126258Smlaier#include <stdio.h>
12126258Smlaier#include <fcntl.h>
13126258Smlaier#include <signal.h>
14126258Smlaier#include <stdlib.h>
15126258Smlaier#include <netdb.h>
16126258Smlaier#include <string.h>
17126258Smlaier#include <sys/types.h>
18126258Smlaier#include <sys/time.h>
19126258Smlaier#include <sys/socket.h>
20126258Smlaier#include <netinet/in.h>
21126258Smlaier#include <netinet/in_systm.h>
22126258Smlaier#include <netinet/ip.h>
23126258Smlaier#include <netinet/tcp.h>
24126258Smlaier#include <netinet/udp.h>
25126258Smlaier#include <netinet/ip_icmp.h>
26126258Smlaier#ifndef	linux
27126258Smlaier#include <netinet/ip_var.h>
28126258Smlaier#include <netinet/tcpip.h>
29126258Smlaier#endif
30126258Smlaier#include "ip_compat.h"
31126258Smlaier#ifdef	linux
32126258Smlaier#include <linux/sockios.h>
33126258Smlaier#include "tcpip.h"
34126258Smlaier#endif
35126258Smlaier#include "ipsd.h"
36126258Smlaier
37126258Smlaier#ifndef	lint
38240233Sglebiusstatic	char	sccsid[] = "@(#)ipsd.c	1.3 12/3/95 (C)1995 Darren Reed";
39171168Smlaier#endif
40171168Smlaier
41126261Smlaierextern	char	*optarg;
42240233Sglebiusextern	int	optind;
43240233Sglebius
44126261Smlaier#ifdef	linux
45126261Smlaierchar	default_device[] = "eth0";
46153110Sru#else
47126258Smlaier# ifdef	sun
48240233Sglebiuschar	default_device[] = "le0";
49240233Sglebius# else
50240233Sglebius#  ifdef	ultrix
51240233Sglebiuschar	default_device[] = "ln0";
52240233Sglebius#  else
53240233Sglebiuschar	default_device[] = "lan0";
54240233Sglebius#  endif
55126258Smlaier# endif
56240233Sglebius#endif
57240233Sglebius
58240233Sglebius#define	NPORTS	21
59126258Smlaier
60126261Smlaieru_short	defports[NPORTS] = {
61240233Sglebius		  7,   9,  20,  21,  23,  25,  53,  69,  79, 111,
62240233Sglebius		123, 161, 162, 512, 513, 514, 515, 520, 540, 6000, 0
63126258Smlaier	};
64126258Smlaier
65126258Smlaieripsd_t	*iphits[NPORTS];
66126258Smlaierint	writes = 0;
67171168Smlaier
68240233Sglebius
69126258Smlaierint	ipcmp(sh1, sh2)
70240233Sglebiussdhit_t	*sh1, *sh2;
71240233Sglebius{
72240233Sglebius	return sh1->sh_ip.s_addr - sh2->sh_ip.s_addr;
73240233Sglebius}
74240233Sglebius
75240233Sglebius
76126258Smlaier/*
77126258Smlaier * Check to see if we've already received a packet from this host for this
78240233Sglebius * port.
79240233Sglebius */
80240233Sglebiusint	findhit(ihp, src, dport)
81126258Smlaieripsd_t	*ihp;
82126258Smlaierstruct	in_addr	src;
83240233Sglebiusu_short	dport;
84126258Smlaier{
85126258Smlaier	int	i, j, k;
86126258Smlaier	sdhit_t	*sh;
87240233Sglebius
88126258Smlaier	sh = NULL;
89126258Smlaier
90240494Sglebius	if (ihp->sd_sz == 4) {
91240494Sglebius		for (i = 0, sh = ihp->sd_hit; i < ihp->sd_cnt; i++, sh++)
92126258Smlaier			if (src.s_addr == sh->sh_ip.s_addr)
93126258Smlaier				return 1;
94126258Smlaier	} else {
95126258Smlaier		for (i = ihp->sd_cnt / 2, j = (i / 2) - 1; j >= 0; j--) {
96126261Smlaier			k = ihp->sd_hit[i].sh_ip.s_addr - src.s_addr;
97126261Smlaier			if (!k)
98126258Smlaier				return 1;
99126258Smlaier			else if (k < 0)
100126261Smlaier				i -= j;
101163606Srwatson			else
102126258Smlaier				i += j;
103223637Sbz		}
104126258Smlaier	}
105126258Smlaier	return 0;
106126258Smlaier}
107126258Smlaier
108126258Smlaier
109223637Sbz/*
110223637Sbz * Search for port number amongst the sorted array of targets we're
111223637Sbz * interested in.
112223637Sbz */
113223637Sbzint	detect(ip, tcp)
114223637Sbzip_t	*ip;
115223637Sbztcphdr_t	*tcp;
116223637Sbz{
117223637Sbz	ipsd_t	*ihp;
118223637Sbz	sdhit_t	*sh;
119223637Sbz	int	i, j, k;
120223637Sbz
121223637Sbz	for (i = 10, j = 4; j >= 0; j--) {
122223637Sbz		k = tcp->th_dport - defports[i];
123223637Sbz		if (!k) {
124223637Sbz			ihp = iphits[i];
125223637Sbz			if (findhit(ihp, ip->ip_src, tcp->th_dport))
126223637Sbz				return 0;
127223637Sbz			sh = ihp->sd_hit + ihp->sd_cnt;
128223637Sbz			sh->sh_date = time(NULL);
129223637Sbz			sh->sh_ip.s_addr = ip->ip_src.s_addr;
130240233Sglebius			if (++ihp->sd_cnt == ihp->sd_sz)
131240233Sglebius			{
132240233Sglebius				ihp->sd_sz += 8;
133240233Sglebius				sh = realloc(sh, ihp->sd_sz * sizeof(*sh));
134240233Sglebius				ihp->sd_hit = sh;
135240233Sglebius			}
136240233Sglebius			qsort(sh, ihp->sd_cnt, sizeof(*sh), ipcmp);
137240233Sglebius			return 0;
138240233Sglebius		}
139240233Sglebius		if (k < 0)
140240233Sglebius			i -= j;
141240233Sglebius		else
142240233Sglebius			i += j;
143240233Sglebius	}
144240233Sglebius	return -1;
145240233Sglebius}
146240233Sglebius
147240233Sglebius
148240233Sglebius/*
149240233Sglebius * Allocate initial storage for hosts
150240233Sglebius */
151240233Sglebiussetuphits()
152240233Sglebius{
153240233Sglebius	int	i;
154240233Sglebius
155240233Sglebius	for (i = 0; i < NPORTS; i++) {
156223637Sbz		if (iphits[i]) {
157240233Sglebius			if (iphits[i]->sd_hit)
158240233Sglebius				free(iphits[i]->sd_hit);
159240233Sglebius			free(iphits[i]);
160126258Smlaier		}
161240233Sglebius		iphits[i] = (ipsd_t *)malloc(sizeof(ipsd_t));
162240233Sglebius		iphits[i]->sd_port = defports[i];
163240233Sglebius		iphits[i]->sd_cnt = 0;
164126258Smlaier		iphits[i]->sd_sz = 4;
165240233Sglebius		iphits[i]->sd_hit = (sdhit_t *)malloc(sizeof(sdhit_t) * 4);
166240811Sglebius	}
167240233Sglebius}
168240811Sglebius
169240811Sglebius
170240233Sglebius/*
171240233Sglebius * cleanup exits
172240233Sglebius */
173240811Sglebiuswaiter()
174240233Sglebius{
175223637Sbz	wait(0);
176240811Sglebius}
177240811Sglebius
178240811Sglebius
179240811Sglebius/*
180240811Sglebius * Write statistics out to a file
181126261Smlaier */
182240811Sglebiuswritestats(nwrites)
183240811Sglebiusint	nwrites;
184240811Sglebius{
185126258Smlaier	ipsd_t	**ipsd, *ips;
186240233Sglebius	char	fname[32];
187240233Sglebius	int	i, fd;
188240233Sglebius
189240233Sglebius	(void) sprintf(fname, "/var/log/ipsd/ipsd-hits.%d", nwrites);
190240233Sglebius	fd = open(fname, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0644);
191240233Sglebius	for (i = 0, ipsd = iphits; i < NPORTS; i++, ipsd++) {
192240233Sglebius		ips = *ipsd;
193240233Sglebius		if (ips->sd_cnt) {
194240233Sglebius			write(fd, ips, sizeof(ipsd_t));
195240233Sglebius			write(fd, ips->sd_hit, sizeof(sdhit_t) * ips->sd_sz);
196240233Sglebius		}
197240233Sglebius	}
198240233Sglebius	(void) close(fd);
199240233Sglebius	exit(0);
200240233Sglebius}
201240233Sglebius
202240233Sglebius
203240233Sglebiusvoid writenow()
204240233Sglebius{
205145836Smlaier	signal(SIGCHLD, waiter);
206240233Sglebius	switch (fork())
207240233Sglebius	{
208145836Smlaier	case 0 :
209240233Sglebius		writestats(writes);
210126258Smlaier		exit(0);
211126258Smlaier	case -1 :
212240233Sglebius		perror("vfork");
213171168Smlaier		break;
214240233Sglebius	default :
215126258Smlaier		writes++;
216126258Smlaier		setuphits();
217126258Smlaier		break;
218240233Sglebius	}
219162238Scsjp}
220126258Smlaier
221126258Smlaier
222145836Smlaiervoid	usage(prog)
223240233Sglebiuschar	*prog;
224223637Sbz{
225126258Smlaier	fprintf(stderr, "Usage: %s [-d device]\n", prog);
226240233Sglebius	exit(1);
227240233Sglebius}
228240233Sglebius
229240233Sglebius
230240233Sglebiusvoid detecthits(fd, writecount)
231240233Sglebiusint fd, writecount;
232240233Sglebius{
233130613Smlaier	struct	in_addr	ip;
234240233Sglebius	int	hits = 0;
235240233Sglebius
236240233Sglebius	while (1) {
237223637Sbz		hits += readloop(fd, ip);
238223637Sbz		if (hits > writecount) {
239223637Sbz			writenow();
240223637Sbz			hits = 0;
241223637Sbz		}
242223637Sbz	}
243240233Sglebius}
244130613Smlaier
245126258Smlaier
246126258Smlaiermain(argc, argv)
247240233Sglebiusint	argc;
248200930Sdelphijchar	*argv[];
249200930Sdelphij{
250200930Sdelphij	char	c, *name =  argv[0], *dev = NULL;
251240233Sglebius	int	fd, writeafter = 10000, angelic = 0;
252200930Sdelphij
253200930Sdelphij	while ((c = getopt(argc, argv, "ad:n:")) != -1)
254240233Sglebius		switch (c)
255130613Smlaier		{
256126258Smlaier		case 'a' :
257240233Sglebius			angelic = 1;
258130613Smlaier			break;
259126258Smlaier		case 'd' :
260240233Sglebius			dev = optarg;
261130613Smlaier			break;
262145836Smlaier		case 'n' :
263240233Sglebius			writeafter = atoi(optarg);
264223637Sbz			break;
265240233Sglebius		default :
266126258Smlaier			fprintf(stderr, "Unknown option \"%c\"\n", c);
267240233Sglebius			usage(name);
268126258Smlaier		}
269240233Sglebius
270231852Sbz	bzero(iphits, sizeof(iphits));
271240233Sglebius	setuphits();
272126258Smlaier
273240233Sglebius	if (!dev)
274126258Smlaier		dev = default_device;
275240233Sglebius	printf("Device:  %s\n", dev);
276223637Sbz	fd = initdevice(dev, 60);
277240233Sglebius
278126258Smlaier	if (!angelic) {
279240233Sglebius		switch (fork())
280240233Sglebius		{
281240233Sglebius		case 0 :
282240811Sglebius			(void) close(0);
283240233Sglebius			(void) close(1);
284240233Sglebius			(void) close(2);
285241039Sglebius			(void) setpgrp(0, getpgrp());
286240233Sglebius			(void) setsid();
287240233Sglebius			break;
288240233Sglebius		case -1:
289240233Sglebius			perror("fork");
290240233Sglebius			exit(-1);
291240233Sglebius		default:
292240233Sglebius			exit(0);
293240233Sglebius		}
294240233Sglebius	}
295240233Sglebius	signal(SIGUSR1, writenow);
296240233Sglebius	detecthits(fd, writeafter);
297240233Sglebius}
298240233Sglebius