/*- * Copyright (c) 2001, 2002, 2006 Lev Walkin . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: import.c,v 1.23 2006/11/21 14:56:36 vlm Exp $ */ #include "ipcad.h" #include "cfgvar.h" #include "service.h" #include "opt.h" #include "storage.h" int import_table(char *dump_file, FILE *msgstream, int clear) { const int check_owner = 1; long entries = 0; struct in_addr src, dst; time_t a_d_a = 0; /* Accounting data age */ char buf[9][256]; struct stat sb; flow_t flow; FILE *f; if(!dump_file || (!conf->chroot_to && *dump_file != '/') || strstr(dump_file, "/..") || !strncmp(dump_file, "/etc/", 5) || !strncmp(dump_file, "/dev/", 5) ) { fprintf(msgstream, "Incomplete (incorrect) pathname\n"); return -1; } f = fopen(dump_file, "r"); if(!f) { fprintf(msgstream, "Can't open dump file %s\n", dump_file); return -1; } if( try_lock(fileno(f), 0) ) { fprintf(msgstream, "Can't lock(\"%s\").\n", dump_file); fclose(f); return -1; } if(fstat(fileno(f), &sb) != 0) { fprintf(msgstream, "Can't fstat(\"%s\").\n", dump_file); fclose(f); return -1; } if((sb.st_mode & S_IFMT) != S_IFREG) { fprintf(msgstream, "%s: Not a regular file.\n", dump_file); fclose(f); return -1; } if(check_owner) { uid_t should_be = conf->set_uid; if((int)should_be <= 0) should_be = getuid(); if(sb.st_uid != should_be) { fprintf(msgstream, "Invalid dump file owner: " "%ld should be %ld.\n", (long)sb.st_uid, (long)should_be ); fclose(f); return -1; } } if((sb.st_mode & 0077)) { fprintf(msgstream, "Insecure dump file permissions. " "Try `chmod 600 %s`\n", dump_file); fclose(f); return -1; } if((sb.st_size < 16)) { fprintf(msgstream, "Warning: %s: empty file.\n", dump_file); fclose(f); return -1; } if(!(a_d_a = sb.st_mtime)) /* Accounting data age */ time(&a_d_a); /* * Read entire file into the storage. */ entries = 0; if(clear) { clear_storage(&active_storage, 0); } #define ADA "Accounting data age is " #define ADA_SIZE sizeof(ADA)-1 #define ADT "Accounting data saved " #define ADT_SIZE sizeof(ADT)-1 memset(&flow, 0, sizeof(flow)); while( fgets(buf[0], sizeof(buf[0]), f) ) { int tokens; if(buf[0][0] == 'A') { if(strncmp(buf[0], ADA, ADA_SIZE) == 0) { a_d_a -= 60*strtol(buf[0] + ADA_SIZE, NULL, 10); } else if(strncmp(buf[0], ADT, ADT_SIZE) == 0) { a_d_a -= sb.st_mtime; a_d_a += strtol(buf[0] + ADT_SIZE, NULL, 10); } continue; } if(buf[0][0] != ' ') continue; tokens = sscanf(buf[0], " %s %s %s %s %s %s %s %s", buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], /* Ports */ buf[7], /* Protocol */ buf[8] /* Interface name */ ); if(tokens != 4 && tokens != 8) continue; /* * Source and destination IP addresses. */ if(inet_aton(buf[1], &src) != 1) continue; if(inet_aton(buf[2], &dst) != 1) continue; errno = 0; flow.src = src; flow.dst = dst; if(tokens == 8) { flow.src_port = atoi(buf[5]); flow.dst_port = atoi(buf[6]); flow.ip_p = atoi(buf[7]); strncpy(flow.ifInName, buf[8], sizeof(flow.ifInName)); flow.ifInName[sizeof(flow.ifInName) - 1] = '\0'; } else { flow.src_port = -1; flow.dst_port = -1; flow.ip_p = 0; flow.ifInName[0] = '\0'; } flow.ifInIndex = -1; flow.ifOutIndex = -1; flow.packets = strtoul(buf[3], NULL, 10); flow.bytes = strtoull(buf[4], NULL, 10); if(errno) /* strtouX error */ continue; flow_update(&active_storage, &flow, AGG_ALL); entries++; } fclose(f); if(clear) { active_storage.create_time = a_d_a; } if(!entries) { fprintf(msgstream, "No valid entries found in %s.\n", dump_file); return 0; } fprintf(msgstream, "%s %ld elements from %s.\n", clear ? "Got" : "Added", entries, dump_file); if(clear && entries) { /* Analyse hash for collisions */ double sumsq = 0.0; double sum = 0.0; int longest_chain = 0; int longest_chain_no = 0; int numbuckets; int bucket; /* Bucket number */ lock_storage(&active_storage); for(bucket = 0; bucket < active_storage.numbuckets; bucket++) { int chainLength = 0; flow_el_t *cur; /* Allow others to run... */ unlock_storage(&active_storage); lock_storage(&active_storage); for(cur = active_storage.buckets[bucket]; cur; cur = cur->bucket_next) chainLength++; if(longest_chain < chainLength) { longest_chain = chainLength; longest_chain_no = bucket; } sumsq += ((double)chainLength) * chainLength; sum += chainLength; } numbuckets = active_storage.numbuckets; unlock_storage(&active_storage); fprintf(stderr, "Storage: chained %d in %d bucket out of %d, mean %.1f dev^2 %.1f\n", longest_chain, longest_chain_no, numbuckets, sum / numbuckets, sumsq / numbuckets - (sum * sum / numbuckets / numbuckets) ); } return 0; }