1/* $FreeBSD$ */ 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 36static const char sccsid[] = "@(#)ipsd.c 1.3 12/3/95 (C)1995 Darren Reed"; 37static const char rcsid[] = "@(#)$Id$"; 38#endif 39 40extern char *optarg; 41extern int optind; 42 43#ifdef linux 44char default_device[] = "eth0"; 45#else 46# ifdef sun 47char default_device[] = "le0"; 48# else 49# ifdef ultrix 50char default_device[] = "ln0"; 51# else 52char default_device[] = "lan0"; 53# endif 54# endif 55#endif 56 57#define NPORTS 21 58 59u_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 64ipsd_t *iphits[NPORTS]; 65int writes = 0; 66 67 68int 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 */ 79int 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 */ 112int 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 */ 150setuphits() 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 */ 172waiter() 173{ 174 wait(0); 175} 176 177 178/* 179 * Write statistics out to a file 180 */ 181writestats(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 202void 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 221void usage(prog) 222 char *prog; 223{ 224 fprintf(stderr, "Usage: %s [-d device]\n", prog); 225 exit(1); 226} 227 228 229void 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 245main(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