ipsd.c revision 31183
1114402Sru/*
2114402Sru * (C)opyright 1995-1997 Darren Reed.
3114402Sru *
4114402Sru * Redistribution and use in source and binary forms are permitted
5114402Sru * provided that this notice is preserved and due credit is given
6114402Sru * to the original author and the contributors.
7114402Sru *
8114402Sru *   The author of this software makes no garuntee about the
9114402Sru * performance of this package or its suitability to fulfill any purpose.
10114402Sru *
11114402Sru */
12114402Sru#include <stdio.h>
13114402Sru#include <fcntl.h>
14114402Sru#include <signal.h>
15114402Sru#include <stdlib.h>
16114402Sru#include <netdb.h>
17114402Sru#include <string.h>
18114402Sru#include <sys/types.h>
19151497Sru#include <sys/time.h>
20114402Sru#include <sys/socket.h>
21114402Sru#include <netinet/in.h>
22114402Sru#include <netinet/in_systm.h>
23114402Sru#include <netinet/ip.h>
24114402Sru#include <netinet/tcp.h>
25114402Sru#include <netinet/udp.h>
26114402Sru#include <netinet/ip_icmp.h>
27114402Sru#ifndef	linux
28114402Sru#include <netinet/ip_var.h>
29114402Sru#include <netinet/tcpip.h>
30114402Sru#endif
31114402Sru#include "ip_compat.h"
32114402Sru#ifdef	linux
33114402Sru#include <linux/sockios.h>
34114402Sru#include "tcpip.h"
35114402Sru#endif
36114402Sru#include "ipsd.h"
37114402Sru
38114402Sru#ifndef	lint
39114402Srustatic const char sccsid[] = "@(#)ipsd.c	1.3 12/3/95 (C)1995 Darren Reed";
40114402Srustatic const char rcsid[] = "@(#)$Id: ipsd.c,v 2.0.2.4 1997/09/28 07:13:17 darrenr Exp $";
41114402Sru#endif
42114402Sru
43114402Sruextern	char	*optarg;
44114402Sruextern	int	optind;
45114402Sru
46114402Sru#ifdef	linux
47114402Sruchar	default_device[] = "eth0";
48114402Sru#else
49114402Sru# ifdef	sun
50114402Sruchar	default_device[] = "le0";
51114402Sru# else
52114402Sru#  ifdef	ultrix
53114402Sruchar	default_device[] = "ln0";
54114402Sru#  else
55114402Sruchar	default_device[] = "lan0";
56114402Sru#  endif
57114402Sru# endif
58114402Sru#endif
59114402Sru
60114402Sru#define	NPORTS	21
61114402Sru
62114402Sruu_short	defports[NPORTS] = {
63114402Sru		  7,   9,  20,  21,  23,  25,  53,  69,  79, 111,
64114402Sru		123, 161, 162, 512, 513, 514, 515, 520, 540, 6000, 0
65114402Sru	};
66114402Sru
67114402Sruipsd_t	*iphits[NPORTS];
68114402Sruint	writes = 0;
69114402Sru
70114402Sru
71114402Sruint	ipcmp(sh1, sh2)
72114402Srusdhit_t	*sh1, *sh2;
73114402Sru{
74114402Sru	return sh1->sh_ip.s_addr - sh2->sh_ip.s_addr;
75114402Sru}
76114402Sru
77114402Sru
78114402Sru/*
79114402Sru * Check to see if we've already received a packet from this host for this
80114402Sru * port.
81114402Sru */
82114402Sruint	findhit(ihp, src, dport)
83114402Sruipsd_t	*ihp;
84114402Srustruct	in_addr	src;
85114402Sruu_short	dport;
86114402Sru{
87114402Sru	int	i, j, k;
88114402Sru	sdhit_t	*sh;
89114402Sru
90114402Sru	sh = NULL;
91114402Sru
92114402Sru	if (ihp->sd_sz == 4) {
93114402Sru		for (i = 0, sh = ihp->sd_hit; i < ihp->sd_cnt; i++, sh++)
94114402Sru			if (src.s_addr == sh->sh_ip.s_addr)
95114402Sru				return 1;
96114402Sru	} else {
97114402Sru		for (i = ihp->sd_cnt / 2, j = (i / 2) - 1; j >= 0; j--) {
98114402Sru			k = ihp->sd_hit[i].sh_ip.s_addr - src.s_addr;
99114402Sru			if (!k)
100114402Sru				return 1;
101114402Sru			else if (k < 0)
102114402Sru				i -= j;
103114402Sru			else
104114402Sru				i += j;
105114402Sru		}
106114402Sru	}
107114402Sru	return 0;
108114402Sru}
109114402Sru
110114402Sru
111114402Sru/*
112114402Sru * Search for port number amongst the sorted array of targets we're
113114402Sru * interested in.
114114402Sru */
115114402Sruint	detect(ip, tcp)
116114402Sruip_t	*ip;
117114402Srutcphdr_t	*tcp;
118114402Sru{
119114402Sru	ipsd_t	*ihp;
120114402Sru	sdhit_t	*sh;
121114402Sru	int	i, j, k;
122114402Sru
123114402Sru	for (i = 10, j = 4; j >= 0; j--) {
124114402Sru		k = tcp->th_dport - defports[i];
125114402Sru		if (!k) {
126114402Sru			ihp = iphits[i];
127114402Sru			if (findhit(ihp, ip->ip_src, tcp->th_dport))
128114402Sru				return 0;
129114402Sru			sh = ihp->sd_hit + ihp->sd_cnt;
130114402Sru			sh->sh_date = time(NULL);
131114402Sru			sh->sh_ip.s_addr = ip->ip_src.s_addr;
132114402Sru			if (++ihp->sd_cnt == ihp->sd_sz)
133114402Sru			{
134114402Sru				ihp->sd_sz += 8;
135114402Sru				sh = realloc(sh, ihp->sd_sz * sizeof(*sh));
136114402Sru				ihp->sd_hit = sh;
137114402Sru			}
138114402Sru			qsort(sh, ihp->sd_cnt, sizeof(*sh), ipcmp);
139114402Sru			return 0;
140114402Sru		}
141114402Sru		if (k < 0)
142114402Sru			i -= j;
143114402Sru		else
144114402Sru			i += j;
145114402Sru	}
146114402Sru	return -1;
147114402Sru}
148114402Sru
149114402Sru
150114402Sru/*
151114402Sru * Allocate initial storage for hosts
152114402Sru */
153114402Srusetuphits()
154114402Sru{
155114402Sru	int	i;
156114402Sru
157114402Sru	for (i = 0; i < NPORTS; i++) {
158114402Sru		if (iphits[i]) {
159114402Sru			if (iphits[i]->sd_hit)
160114402Sru				free(iphits[i]->sd_hit);
161114402Sru			free(iphits[i]);
162114402Sru		}
163114402Sru		iphits[i] = (ipsd_t *)malloc(sizeof(ipsd_t));
164114402Sru		iphits[i]->sd_port = defports[i];
165114402Sru		iphits[i]->sd_cnt = 0;
166114402Sru		iphits[i]->sd_sz = 4;
167114402Sru		iphits[i]->sd_hit = (sdhit_t *)malloc(sizeof(sdhit_t) * 4);
168114402Sru	}
169114402Sru}
170114402Sru
171114402Sru
172114402Sru/*
173114402Sru * cleanup exits
174114402Sru */
175114402Sruwaiter()
176114402Sru{
177114402Sru	wait(0);
178114402Sru}
179114402Sru
180114402Sru
181114402Sru/*
182114402Sru * Write statistics out to a file
183114402Sru */
184114402Sruwritestats(nwrites)
185114402Sruint	nwrites;
186114402Sru{
187114402Sru	ipsd_t	**ipsd, *ips;
188114402Sru	char	fname[32];
189114402Sru	int	i, fd;
190114402Sru
191114402Sru	(void) sprintf(fname, "/var/log/ipsd/ipsd-hits.%d", nwrites);
192114402Sru	fd = open(fname, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0644);
193114402Sru	for (i = 0, ipsd = iphits; i < NPORTS; i++, ipsd++) {
194114402Sru		ips = *ipsd;
195114402Sru		if (ips->sd_cnt) {
196114402Sru			write(fd, ips, sizeof(ipsd_t));
197114402Sru			write(fd, ips->sd_hit, sizeof(sdhit_t) * ips->sd_sz);
198114402Sru		}
199114402Sru	}
200114402Sru	(void) close(fd);
201114402Sru	exit(0);
202114402Sru}
203114402Sru
204114402Sru
205114402Sruvoid writenow()
206114402Sru{
207114402Sru	signal(SIGCHLD, waiter);
208114402Sru	switch (fork())
209114402Sru	{
210114402Sru	case 0 :
211114402Sru		writestats(writes);
212114402Sru		exit(0);
213114402Sru	case -1 :
214114402Sru		perror("vfork");
215114402Sru		break;
216114402Sru	default :
217114402Sru		writes++;
218114402Sru		setuphits();
219114402Sru		break;
220114402Sru	}
221114402Sru}
222114402Sru
223114402Sru
224114402Sruvoid	usage(prog)
225114402Sruchar	*prog;
226114402Sru{
227114402Sru	fprintf(stderr, "Usage: %s [-d device]\n", prog);
228114402Sru	exit(1);
229114402Sru}
230114402Sru
231114402Sru
232114402Sruvoid detecthits(fd, writecount)
233114402Sruint fd, writecount;
234114402Sru{
235114402Sru	struct	in_addr	ip;
236114402Sru	int	hits = 0;
237114402Sru
238	while (1) {
239		hits += readloop(fd, ip);
240		if (hits > writecount) {
241			writenow();
242			hits = 0;
243		}
244	}
245}
246
247
248main(argc, argv)
249int	argc;
250char	*argv[];
251{
252	char	*name =  argv[0], *dev = NULL;
253	int	fd, writeafter = 10000, angelic = 0, c;
254
255	while ((c = getopt(argc, argv, "ad:n:")) != -1)
256		switch (c)
257		{
258		case 'a' :
259			angelic = 1;
260			break;
261		case 'd' :
262			dev = optarg;
263			break;
264		case 'n' :
265			writeafter = atoi(optarg);
266			break;
267		default :
268			fprintf(stderr, "Unknown option \"%c\"\n", c);
269			usage(name);
270		}
271
272	bzero(iphits, sizeof(iphits));
273	setuphits();
274
275	if (!dev)
276		dev = default_device;
277	printf("Device:  %s\n", dev);
278	fd = initdevice(dev, 60);
279
280	if (!angelic) {
281		switch (fork())
282		{
283		case 0 :
284			(void) close(0);
285			(void) close(1);
286			(void) close(2);
287			(void) setpgrp(0, getpgrp());
288			(void) setsid();
289			break;
290		case -1:
291			perror("fork");
292			exit(-1);
293		default:
294			exit(0);
295		}
296	}
297	signal(SIGUSR1, writenow);
298	detecthits(fd, writeafter);
299}
300