| /* |
| * (C)opyright 1995-1998 Darren Reed. |
| * |
| * See the IPFILTER.LICENCE file for details on licencing. |
| * |
| */ |
| #include <stdio.h> |
| #include <fcntl.h> |
| #include <signal.h> |
| #include <stdlib.h> |
| #include <netdb.h> |
| #include <string.h> |
| #include <sys/types.h> |
| #include <sys/time.h> |
| #include <sys/socket.h> |
| #include <netinet/in.h> |
| #include <netinet/in_systm.h> |
| #include <netinet/ip.h> |
| #include <netinet/tcp.h> |
| #include <netinet/udp.h> |
| #include <netinet/ip_icmp.h> |
| #ifndef linux |
| #include <netinet/ip_var.h> |
| #include <netinet/tcpip.h> |
| #endif |
| #include "ip_compat.h" |
| #ifdef linux |
| #include <linux/sockios.h> |
| #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$"; |
| #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); |
| } |