ipsd.c revision 259065
161151Sdcs/*	$FreeBSD: releng/10.0/contrib/ipfilter/ipsd/ipsd.c 255332 2013-09-06 23:11:19Z cy $	*/
261151Sdcs
361151Sdcs/*
461151Sdcs * (C)opyright 1995-1998 Darren Reed.
561151Sdcs *
6221909Suqs * See the IPFILTER.LICENCE file for details on licencing.
795677Sdougb *
895677Sdougb */
995677Sdougb#include <stdio.h>
1061151Sdcs#include <fcntl.h>
1161151Sdcs#include <signal.h>
1261151Sdcs#include <stdlib.h>
1361151Sdcs#include <netdb.h>
1461151Sdcs#include <string.h>
1561151Sdcs#include <sys/types.h>
1661151Sdcs#include <sys/time.h>
1761151Sdcs#include <sys/socket.h>
1861151Sdcs#include <netinet/in.h>
1961151Sdcs#include <netinet/in_systm.h>
2061151Sdcs#include <netinet/ip.h>
2161151Sdcs#include <netinet/tcp.h>
2261151Sdcs#include <netinet/udp.h>
2395677Sdougb#include <netinet/ip_icmp.h>
2461151Sdcs#ifndef	linux
2561151Sdcs#include <netinet/ip_var.h>
2661151Sdcs#include <netinet/tcpip.h>
2761151Sdcs#endif
2861151Sdcs#include "ip_compat.h"
2961151Sdcs#ifdef	linux
3061151Sdcs#include <linux/sockios.h>
3195677Sdougb#include "tcpip.h"
3261151Sdcs#endif
3361151Sdcs#include "ipsd.h"
3495677Sdougb
3561151Sdcs#ifndef	lint
3661151Sdcsstatic const char sccsid[] = "@(#)ipsd.c	1.3 12/3/95 (C)1995 Darren Reed";
3761151Sdcsstatic const char rcsid[] = "@(#)$Id$";
3861151Sdcs#endif
3995677Sdougb
4061151Sdcsextern	char	*optarg;
4195677Sdougbextern	int	optind;
42175017Sdougb
4361151Sdcs#ifdef	linux
4461151Sdcschar	default_device[] = "eth0";
4561151Sdcs#else
4661151Sdcs# ifdef	sun
47106711Sdcschar	default_device[] = "le0";
48106711Sdcs# else
49106711Sdcs#  ifdef	ultrix
50106711Sdcschar	default_device[] = "ln0";
51106711Sdcs#  else
52106711Sdcschar	default_device[] = "lan0";
53106711Sdcs#  endif
54106711Sdcs# endif
55106711Sdcs#endif
56106711Sdcs
57106711Sdcs#define	NPORTS	21
58106711Sdcs
59106711Sdcsu_short	defports[NPORTS] = {
60106711Sdcs		  7,   9,  20,  21,  23,  25,  53,  69,  79, 111,
61106711Sdcs		123, 161, 162, 512, 513, 514, 515, 520, 540, 6000, 0
62106711Sdcs	};
63106711Sdcs
64106711Sdcsipsd_t	*iphits[NPORTS];
65106711Sdcsint	writes = 0;
66106711Sdcs
67106711Sdcs
68106711Sdcsint	ipcmp(sh1, sh2)
69106711Sdcs	sdhit_t	*sh1, *sh2;
70106746Sdcs{
71106711Sdcs	return sh1->sh_ip.s_addr - sh2->sh_ip.s_addr;
72106711Sdcs}
73106711Sdcs
74106711Sdcs
75106711Sdcs/*
76106711Sdcs * Check to see if we've already received a packet from this host for this
77106711Sdcs * port.
78106711Sdcs */
79106711Sdcsint	findhit(ihp, src, dport)
80106711Sdcs	ipsd_t	*ihp;
81106711Sdcs	struct	in_addr	src;
82106711Sdcs	u_short	dport;
83106711Sdcs{
84106711Sdcs	int	i, j, k;
85106711Sdcs	sdhit_t	*sh;
86106711Sdcs
87106711Sdcs	sh = NULL;
88106711Sdcs
89106711Sdcs	if (ihp->sd_sz == 4) {
90106711Sdcs		for (i = 0, sh = ihp->sd_hit; i < ihp->sd_cnt; i++, sh++)
91106711Sdcs			if (src.s_addr == sh->sh_ip.s_addr)
92106711Sdcs				return 1;
93106711Sdcs	} else {
94106711Sdcs		for (i = ihp->sd_cnt / 2, j = (i / 2) - 1; j >= 0; j--) {
95106711Sdcs			k = ihp->sd_hit[i].sh_ip.s_addr - src.s_addr;
96106711Sdcs			if (!k)
97106711Sdcs				return 1;
98106711Sdcs			else if (k < 0)
99106711Sdcs				i -= j;
100106711Sdcs			else
101106711Sdcs				i += j;
102106711Sdcs		}
103106711Sdcs	}
104106711Sdcs	return 0;
105106711Sdcs}
106106711Sdcs
107106711Sdcs
108106711Sdcs/*
109106711Sdcs * Search for port number amongst the sorted array of targets we're
110106711Sdcs * interested in.
111106711Sdcs */
112106711Sdcsint	detect(ip, tcp)
113106711Sdcs	ip_t	*ip;
114106711Sdcs	tcphdr_t	*tcp;
115106711Sdcs{
116106711Sdcs	ipsd_t	*ihp;
117106711Sdcs	sdhit_t	*sh;
118106711Sdcs	int	i, j, k;
119106746Sdcs
120106746Sdcs	for (i = 10, j = 4; j >= 0; j--) {
121106746Sdcs		k = tcp->th_dport - defports[i];
122106746Sdcs		if (!k) {
123106746Sdcs			ihp = iphits[i];
124106746Sdcs			if (findhit(ihp, ip->ip_src, tcp->th_dport))
125106746Sdcs				return 0;
126106746Sdcs			sh = ihp->sd_hit + ihp->sd_cnt;
127106746Sdcs			sh->sh_date = time(NULL);
128106746Sdcs			sh->sh_ip.s_addr = ip->ip_src.s_addr;
129106746Sdcs			if (++ihp->sd_cnt == ihp->sd_sz)
130106746Sdcs			{
131106746Sdcs				ihp->sd_sz += 8;
132106746Sdcs				sh = realloc(sh, ihp->sd_sz * sizeof(*sh));
133106746Sdcs				ihp->sd_hit = sh;
134106746Sdcs			}
135106746Sdcs			qsort(sh, ihp->sd_cnt, sizeof(*sh), ipcmp);
136106746Sdcs			return 0;
137106746Sdcs		}
138106746Sdcs		if (k < 0)
139106746Sdcs			i -= j;
140106746Sdcs		else
141106746Sdcs			i += j;
142106746Sdcs	}
143106746Sdcs	return -1;
144106746Sdcs}
145106746Sdcs
146106746Sdcs
147106746Sdcs/*
148106746Sdcs * Allocate initial storage for hosts
149106746Sdcs */
150106746Sdcssetuphits()
151106746Sdcs{
152106746Sdcs	int	i;
153106746Sdcs
154106746Sdcs	for (i = 0; i < NPORTS; i++) {
155106746Sdcs		if (iphits[i]) {
156106746Sdcs			if (iphits[i]->sd_hit)
157106746Sdcs				free(iphits[i]->sd_hit);
158106746Sdcs			free(iphits[i]);
159106746Sdcs		}
160106746Sdcs		iphits[i] = (ipsd_t *)malloc(sizeof(ipsd_t));
161106746Sdcs		iphits[i]->sd_port = defports[i];
162106746Sdcs		iphits[i]->sd_cnt = 0;
163106746Sdcs		iphits[i]->sd_sz = 4;
164106746Sdcs		iphits[i]->sd_hit = (sdhit_t *)malloc(sizeof(sdhit_t) * 4);
165106746Sdcs	}
166106746Sdcs}
167106746Sdcs
168106746Sdcs
169106746Sdcs/*
170106746Sdcs * cleanup exits
171106746Sdcs */
172106746Sdcswaiter()
173106746Sdcs{
174106746Sdcs	wait(0);
175106746Sdcs}
176106746Sdcs
177106746Sdcs
178106746Sdcs/*
179106746Sdcs * Write statistics out to a file
180106746Sdcs */
181106746Sdcswritestats(nwrites)
182106746Sdcs	int	nwrites;
183106746Sdcs{
184106746Sdcs	ipsd_t	**ipsd, *ips;
185106746Sdcs	char	fname[32];
186106746Sdcs	int	i, fd;
187106746Sdcs
188106746Sdcs	(void) sprintf(fname, "/var/log/ipsd/ipsd-hits.%d", nwrites);
189106746Sdcs	fd = open(fname, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0644);
190106746Sdcs	for (i = 0, ipsd = iphits; i < NPORTS; i++, ipsd++) {
191106746Sdcs		ips = *ipsd;
192106746Sdcs		if (ips->sd_cnt) {
193106746Sdcs			write(fd, ips, sizeof(ipsd_t));
194106746Sdcs			write(fd, ips->sd_hit, sizeof(sdhit_t) * ips->sd_sz);
195106746Sdcs		}
196106746Sdcs	}
197106746Sdcs	(void) close(fd);
198106746Sdcs	exit(0);
199106746Sdcs}
200106746Sdcs
201106746Sdcs
202106746Sdcsvoid writenow()
203106746Sdcs{
204106746Sdcs	signal(SIGCHLD, waiter);
205106746Sdcs	switch (fork())
206106746Sdcs	{
207106746Sdcs	case 0 :
208106746Sdcs		writestats(writes);
209106746Sdcs		exit(0);
210106746Sdcs	case -1 :
211106746Sdcs		perror("vfork");
212106746Sdcs		break;
213106746Sdcs	default :
214106746Sdcs		writes++;
215106746Sdcs		setuphits();
216106746Sdcs		break;
217106746Sdcs	}
218175017Sdougb}
219106746Sdcs
220106746Sdcs
221106746Sdcsvoid	usage(prog)
222106746Sdcs	char	*prog;
223106746Sdcs{
224106746Sdcs	fprintf(stderr, "Usage: %s [-d device]\n", prog);
225106746Sdcs	exit(1);
226106746Sdcs}
227106746Sdcs
228106746Sdcs
229106746Sdcsvoid detecthits(fd, writecount)
230106746Sdcs	int fd, writecount;
231106746Sdcs{
232106746Sdcs	struct	in_addr	ip;
233106746Sdcs	int	hits = 0;
234106746Sdcs
235106746Sdcs	while (1) {
236106746Sdcs		hits += readloop(fd, ip);
237106746Sdcs		if (hits > writecount) {
238106746Sdcs			writenow();
239106746Sdcs			hits = 0;
240106746Sdcs		}
241106746Sdcs	}
242106746Sdcs}
243106746Sdcs
244106746Sdcs
245106746Sdcsmain(argc, argv)
246106746Sdcs	int	argc;
247106746Sdcs	char	*argv[];
248106746Sdcs{
249106746Sdcs	char	*name =  argv[0], *dev = NULL;
250106746Sdcs	int	fd, writeafter = 10000, angelic = 0, c;
251106746Sdcs
252106746Sdcs	while ((c = getopt(argc, argv, "ad:n:")) != -1)
253106746Sdcs		switch (c)
254106746Sdcs		{
255106746Sdcs		case 'a' :
256106746Sdcs			angelic = 1;
257106746Sdcs			break;
258106746Sdcs		case 'd' :
259106746Sdcs			dev = optarg;
260106746Sdcs			break;
261106746Sdcs		case 'n' :
262106746Sdcs			writeafter = atoi(optarg);
263106746Sdcs			break;
264106746Sdcs		default :
265106746Sdcs			fprintf(stderr, "Unknown option \"%c\"\n", c);
266106746Sdcs			usage(name);
267106746Sdcs		}
268106746Sdcs
269106746Sdcs	bzero(iphits, sizeof(iphits));
270106746Sdcs	setuphits();
271106746Sdcs
272106746Sdcs	if (!dev)
273106746Sdcs		dev = default_device;
274106746Sdcs	printf("Device:  %s\n", dev);
275106746Sdcs	fd = initdevice(dev, 60);
276106746Sdcs
277106746Sdcs	if (!angelic) {
278106746Sdcs		switch (fork())
279106746Sdcs		{
280106746Sdcs		case 0 :
281106746Sdcs			(void) close(0);
282106746Sdcs			(void) close(1);
283106746Sdcs			(void) close(2);
284106746Sdcs			(void) setpgrp(0, getpgrp());
285106746Sdcs			(void) setsid();
286106746Sdcs			break;
287106746Sdcs		case -1:
288106746Sdcs			perror("fork");
289106746Sdcs			exit(-1);
290106746Sdcs		default:
291106746Sdcs			exit(0);
292106746Sdcs		}
293106746Sdcs	}
294106746Sdcs	signal(SIGUSR1, writenow);
295106746Sdcs	detecthits(fd, writeafter);
296106746Sdcs}
297106746Sdcs