xref: /netbsd-src/external/bsd/ipf/dist/ipsd/ipsd.c (revision 13885a665959c62f13a82b3caedf986eaa17aa31)
1 /*	$NetBSD: ipsd.c,v 1.2 2012/07/22 14:27:35 darrenr Exp $	*/
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
36 static const char sccsid[] = "@(#)ipsd.c	1.3 12/3/95 (C)1995 Darren Reed";
37 static const char rcsid[] = "@(#)Id: ipsd.c,v 1.1.1.2 2012/07/22 13:44:34 darrenr Exp $";
38 #endif
39 
40 extern	char	*optarg;
41 extern	int	optind;
42 
43 #ifdef	linux
44 char	default_device[] = "eth0";
45 #else
46 # ifdef	sun
47 char	default_device[] = "le0";
48 # else
49 #  ifdef	ultrix
50 char	default_device[] = "ln0";
51 #  else
52 char	default_device[] = "lan0";
53 #  endif
54 # endif
55 #endif
56 
57 #define	NPORTS	21
58 
59 u_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 
64 ipsd_t	*iphits[NPORTS];
65 int	writes = 0;
66 
67 
ipcmp(sh1,sh2)68 int	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  */
findhit(ihp,src,dport)79 int	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  */
detect(ip,tcp)112 int	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  */
setuphits()150 setuphits()
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  */
waiter()172 waiter()
173 {
174 	wait(0);
175 }
176 
177 
178 /*
179  * Write statistics out to a file
180  */
writestats(nwrites)181 writestats(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 
writenow()202 void 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 
usage(prog)221 void	usage(prog)
222 	char	*prog;
223 {
224 	fprintf(stderr, "Usage: %s [-d device]\n", prog);
225 	exit(1);
226 }
227 
228 
detecthits(fd,writecount)229 void 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 
main(argc,argv)245 main(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