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 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 */ 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 */ 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 */ 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 */ 172 waiter() 173 { 174 wait(0); 175 } 176 177 178 /* 179 * Write statistics out to a file 180 */ 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 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 221 void usage(prog) 222 char *prog; 223 { 224 fprintf(stderr, "Usage: %s [-d device]\n", prog); 225 exit(1); 226 } 227 228 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 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