/* $NetBSD: ipsd.c,v 1.3 2004/03/28 09:00:55 martti Exp $ */ /* * (C)opyright 1995-1998 Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef linux #include #include #endif #include "ip_compat.h" #ifdef linux #include #include "tcpip.h" #endif #include "ipsd.h" #ifndef lint static const char sccsid[] = "@(#)ipsd.c 1.3 12/3/95 (C)1995 Darren Reed"; static const char rcsid[] = "@(#)Id: ipsd.c,v 2.2 2001/06/09 17:09:25 darrenr Exp"; #endif extern char *optarg; extern int optind; #ifdef linux char default_device[] = "eth0"; #else # ifdef sun char default_device[] = "le0"; # else # ifdef ultrix char default_device[] = "ln0"; # else char default_device[] = "lan0"; # endif # endif #endif #define NPORTS 21 u_short defports[NPORTS] = { 7, 9, 20, 21, 23, 25, 53, 69, 79, 111, 123, 161, 162, 512, 513, 514, 515, 520, 540, 6000, 0 }; ipsd_t *iphits[NPORTS]; int writes = 0; int ipcmp(sh1, sh2) sdhit_t *sh1, *sh2; { return sh1->sh_ip.s_addr - sh2->sh_ip.s_addr; } /* * Check to see if we've already received a packet from this host for this * port. */ int findhit(ihp, src, dport) ipsd_t *ihp; struct in_addr src; u_short dport; { int i, j, k; sdhit_t *sh; sh = NULL; if (ihp->sd_sz == 4) { for (i = 0, sh = ihp->sd_hit; i < ihp->sd_cnt; i++, sh++) if (src.s_addr == sh->sh_ip.s_addr) return 1; } else { for (i = ihp->sd_cnt / 2, j = (i / 2) - 1; j >= 0; j--) { k = ihp->sd_hit[i].sh_ip.s_addr - src.s_addr; if (!k) return 1; else if (k < 0) i -= j; else i += j; } } return 0; } /* * Search for port number amongst the sorted array of targets we're * interested in. */ int detect(ip, tcp) ip_t *ip; tcphdr_t *tcp; { ipsd_t *ihp; sdhit_t *sh; int i, j, k; for (i = 10, j = 4; j >= 0; j--) { k = tcp->th_dport - defports[i]; if (!k) { ihp = iphits[i]; if (findhit(ihp, ip->ip_src, tcp->th_dport)) return 0; sh = ihp->sd_hit + ihp->sd_cnt; sh->sh_date = time(NULL); sh->sh_ip.s_addr = ip->ip_src.s_addr; if (++ihp->sd_cnt == ihp->sd_sz) { ihp->sd_sz += 8; sh = realloc(sh, ihp->sd_sz * sizeof(*sh)); ihp->sd_hit = sh; } qsort(sh, ihp->sd_cnt, sizeof(*sh), ipcmp); return 0; } if (k < 0) i -= j; else i += j; } return -1; } /* * Allocate initial storage for hosts */ setuphits() { int i; for (i = 0; i < NPORTS; i++) { if (iphits[i]) { if (iphits[i]->sd_hit) free(iphits[i]->sd_hit); free(iphits[i]); } iphits[i] = (ipsd_t *)malloc(sizeof(ipsd_t)); iphits[i]->sd_port = defports[i]; iphits[i]->sd_cnt = 0; iphits[i]->sd_sz = 4; iphits[i]->sd_hit = (sdhit_t *)malloc(sizeof(sdhit_t) * 4); } } /* * cleanup exits */ waiter() { wait(0); } /* * Write statistics out to a file */ writestats(nwrites) int nwrites; { ipsd_t **ipsd, *ips; char fname[32]; int i, fd; (void) sprintf(fname, "/var/log/ipsd/ipsd-hits.%d", nwrites); fd = open(fname, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0644); for (i = 0, ipsd = iphits; i < NPORTS; i++, ipsd++) { ips = *ipsd; if (ips->sd_cnt) { write(fd, ips, sizeof(ipsd_t)); write(fd, ips->sd_hit, sizeof(sdhit_t) * ips->sd_sz); } } (void) close(fd); exit(0); } void writenow() { signal(SIGCHLD, waiter); switch (fork()) { case 0 : writestats(writes); exit(0); case -1 : perror("vfork"); break; default : writes++; setuphits(); break; } } void usage(prog) char *prog; { fprintf(stderr, "Usage: %s [-d device]\n", prog); exit(1); } void detecthits(fd, writecount) int fd, writecount; { struct in_addr ip; int hits = 0; while (1) { hits += readloop(fd, ip); if (hits > writecount) { writenow(); hits = 0; } } } main(argc, argv) int argc; char *argv[]; { char *name = argv[0], *dev = NULL; int fd, writeafter = 10000, angelic = 0, c; while ((c = getopt(argc, argv, "ad:n:")) != -1) switch (c) { case 'a' : angelic = 1; break; case 'd' : dev = optarg; break; case 'n' : writeafter = atoi(optarg); break; default : fprintf(stderr, "Unknown option \"%c\"\n", c); usage(name); } bzero(iphits, sizeof(iphits)); setuphits(); if (!dev) dev = default_device; printf("Device: %s\n", dev); fd = initdevice(dev, 60); if (!angelic) { switch (fork()) { case 0 : (void) close(0); (void) close(1); (void) close(2); (void) setpgrp(0, getpgrp()); (void) setsid(); break; case -1: perror("fork"); exit(-1); default: exit(0); } } signal(SIGUSR1, writenow); detecthits(fd, writeafter); }