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