static char *GuessSubDir(char *channeldir, char *filename) { char s[MAXPATHLEN]; struct tm *t_tm; int i; if ( strlen(filename) == 19 && (strncmp(filename, "nfcapd.", 7) == 0) ) { char *p = &filename[7]; time_t t = ISO2UNIX(p); t_tm = localtime(&t); } else return NULL; i = 0; // if the file exists, it must be in any of the possible subdirs // so try one after the next - one will match while ( subdir_def[i] ) { char const *sub_fmt = subdir_def[i]; char subpath[255]; struct stat stat_buf; strftime(subpath, 254, sub_fmt, t_tm); subpath[254] = '\0'; snprintf(s, MAXPATHLEN-1, "%s/%s/%s", channeldir, subpath, filename); if ( stat(s, &stat_buf) == 0 && S_ISREG(stat_buf.st_mode) ) { // found file in subdir return strdup(subpath); } i++; } return NULL; } // End of GuessSubDir
int main( int argc, char **argv ) { int i, c; master_record_t record; nffile_t *nffile; when = ISO2UNIX(strdup("200407111030")); while ((c = getopt(argc, argv, "h")) != EOF) { switch(c) { case 'h': break; default: fprintf(stderr, "ERROR: Unsupported option: '%c'\n", c); exit(255); } } extension_info.map = (extension_map_t *)malloc(sizeof(extension_map_t) + 32 * sizeof(uint16_t)); if ( !extension_info.map ) { fprintf(stderr, "malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno)); exit(255); } extension_info.map->type = ExtensionMapType; extension_info.map->map_id = 0; i = 0; extension_info.map->ex_id[i++] = EX_IO_SNMP_2; extension_info.map->ex_id[i++] = EX_AS_2; extension_info.map->ex_id[i++] = EX_MULIPLE; extension_info.map->ex_id[i++] = EX_NEXT_HOP_v4; extension_info.map->ex_id[i++] = EX_NEXT_HOP_BGP_v4; extension_info.map->ex_id[i++] = EX_VLAN; extension_info.map->ex_id[i++] = EX_OUT_PKG_4; extension_info.map->ex_id[i++] = EX_OUT_BYTES_4; extension_info.map->ex_id[i++] = EX_AGGR_FLOWS_4; extension_info.map->ex_id[i++] = EX_MAC_1; extension_info.map->ex_id[i++] = EX_MAC_2; extension_info.map->ex_id[i++] = EX_MPLS; extension_info.map->ex_id[i++] = EX_ROUTER_IP_v4; extension_info.map->ex_id[i++] = EX_ROUTER_ID; extension_info.map->ex_id[i++] = EX_BGPADJ; extension_info.map->ex_id[i] = 0; extension_info.map->size = sizeof(extension_map_t) + i * sizeof(uint16_t); // align 32bits if (( extension_info.map->size & 0x3 ) != 0 ) { extension_info.map->size += 4 - ( extension_info.map->size & 0x3 ); } extension_info.map->extension_size = 0; i=0; while (extension_info.map->ex_id[i]) { int id = extension_info.map->ex_id[i]; extension_info.map->extension_size += extension_descriptor[id].size; i++; } memset((void *)&record, 0, sizeof(record)); nffile = OpenNewFile("-", NULL, 0, 0, NULL); if ( !nffile ) { exit(255); } AppendToBuffer(nffile, (void *)extension_info.map, extension_info.map->size); record.map_ref = extension_info.map; record.type = CommonRecordType; record.flags = 0; record.exporter_sysid = 1; record.tcp_flags = 1; record.tos = 2; record.fwd_status = 0; record.srcport = 1024; record.dstport = 25; record.prot = IPPROTO_TCP; record.input = 12; record.output = 14; record.srcas = 775; record.dstas = 8404; SetIPaddress(&record, PF_INET, "172.16.1.66", "192.168.170.100"); SetNextIPaddress(&record, PF_INET, "172.72.1.2"); SetBGPNextIPaddress(&record, PF_INET, "172.73.2.3"); SetRouterIPaddress(&record, PF_INET, "127.0.0.1"); record.engine_type = 5; record.engine_id = 6; record.dPkts = 202; record.dOctets = 303; record.dst_tos = 128; record.dir = 1; record.src_mask = 16; record.dst_mask = 24; record.src_vlan = 82; record.dst_vlan = 93; record.out_pkts = 212; record.out_bytes = 3234; record.aggr_flows = 3; record.in_src_mac = 0x0234567890aaLL; record.out_dst_mac = 0xffeeddccbbaaLL; record.out_src_mac = 0xaa3456789002LL; record.in_dst_mac = 0xaaeeddccbbffLL; record.mpls_label[0] = 1010 << 4; record.mpls_label[1] = 2020 << 4; record.mpls_label[2] = 3030 << 4; record.mpls_label[3] = 4040 << 4; record.mpls_label[4] = 5050 << 4; record.mpls_label[5] = 6060 << 4; record.mpls_label[6] = 7070 << 4; record.mpls_label[7] = 8080 << 4; record.mpls_label[8] = 9090 << 4; record.mpls_label[9] = (100100 << 4) + 1; record.client_nw_delay_usec = 2; record.server_nw_delay_usec = 22; record.appl_latency_usec = 222; record.bgpNextAdjacentAS = 45804; record.bgpPrevAdjacentAS = 32775; fprintf(stderr, "IPv4 32bit packets 32bit bytes\n"); UpdateRecord(&record); PackRecord(&record, nffile); SetIPaddress(&record, PF_INET, "172.16.2.66", "192.168.170.101"); fprintf(stderr, "IPv4 32bit packets 32bit bytes\n"); UpdateRecord(&record); PackRecord(&record, nffile); record.dPkts = 101; record.dOctets = 102; fprintf(stderr, "IPv4 32bit packets 32bit bytes\n"); UpdateRecord(&record); PackRecord(&record, nffile); SetIPaddress(&record, PF_INET, "172.16.3.66", "192.168.170.102"); fprintf(stderr, "IPv4 32bit packets 32bit bytes\n"); UpdateRecord(&record); PackRecord(&record, nffile); SetIPaddress(&record, PF_INET, "172.16.4.66", "192.168.170.103"); record.srcport = 2024; record.prot = IPPROTO_UDP; record.tcp_flags = 1; record.tos = 1; record.dPkts = 1001; record.dOctets = 1002; fprintf(stderr, "IPv4 32bit packets 32bit bytes\n"); UpdateRecord(&record); PackRecord(&record, nffile); SetIPaddress(&record, PF_INET, "172.16.5.66", "192.168.170.104"); record.srcport = 3024; record.prot = 51; record.tcp_flags = 2; record.tos = 2; record.dPkts = 10001; record.dOctets = 10002; fprintf(stderr, "IPv4 32bit packets 32bit bytes\n"); UpdateRecord(&record); PackRecord(&record, nffile); SetIPaddress(&record, PF_INET, "172.16.6.66", "192.168.170.105"); record.srcport = 4024; record.prot = IPPROTO_TCP; record.tcp_flags = 4; record.tos = 3; record.dPkts = 100001; record.dOctets = 100002; fprintf(stderr, "IPv4 32bit packets 32bit bytes\n"); UpdateRecord(&record); PackRecord(&record, nffile); SetIPaddress(&record, PF_INET, "172.16.7.66", "192.168.170.106"); record.srcport = 5024; record.tcp_flags = 8; record.tos = 4; record.dPkts = 1000001; record.dOctets = 1000002; fprintf(stderr, "IPv4 32bit packets 32bit bytes\n"); UpdateRecord(&record); PackRecord(&record, nffile); SetIPaddress(&record, PF_INET, "172.16.8.66", "192.168.170.107"); record.tcp_flags = 1; record.tos = 4; record.dPkts = 10000001; record.dOctets = 1001; fprintf(stderr, "IPv4 32bit packets 32bit bytes\n"); UpdateRecord(&record); PackRecord(&record, nffile); SetIPaddress(&record, PF_INET, "172.16.9.66", "192.168.170.108"); record.srcport = 6024; record.tcp_flags = 16; record.tos = 5; record.dPkts = 500; record.dOctets = 10000001; fprintf(stderr, "IPv4 32bit packets 32bit bytes\n"); UpdateRecord(&record); PackRecord(&record, nffile); SetIPaddress(&record, PF_INET, "172.16.10.66", "192.168.170.109"); fprintf(stderr, "IPv4 32bit packets 32bit bytes\n"); UpdateRecord(&record); PackRecord(&record, nffile); SetIPaddress(&record, PF_INET, "172.16.11.66", "192.168.170.110"); record.srcport = 7024; record.tcp_flags = 32; record.tos = 255; record.dPkts = 5000; record.dOctets = 100000001; fprintf(stderr, "IPv4 32bit packets 32bit bytes\n"); UpdateRecord(&record); PackRecord(&record, nffile); SetIPaddress(&record, PF_INET, "172.16.12.66", "192.168.170.111"); record.srcport = 8024; record.tcp_flags = 63; record.tos = 0; record.dOctets = 1000000001; fprintf(stderr, "IPv4 32bit packets 32bit bytes\n"); UpdateRecord(&record); PackRecord(&record, nffile); SetIPaddress(&record, PF_INET, "172.16.13.66", "192.168.170.112"); record.srcport = 0; record.dstport = 8; record.prot = 1; record.tcp_flags = 0; record.tos = 0; record.dPkts = 50002; record.dOctets = 50000; fprintf(stderr, "IPv4 32bit packets 32bit bytes\n"); UpdateRecord(&record); PackRecord(&record, nffile); SetIPaddress(&record, PF_INET, "172.160.160.166", "172.160.160.180"); record.srcport = 10024; record.dstport = 25000; record.prot = IPPROTO_TCP; record.dPkts = 500001; record.dOctets = 500000; fprintf(stderr, "IPv4 32bit packets 32bit bytes\n"); UpdateRecord(&record); PackRecord(&record, nffile); SetIPaddress(&record, PF_INET6, "fe80::2110:abcd:1234:0", "fe80::2110:abcd:1235:4321"); // SetNextIPaddress(&record, PF_INET6, "2003:234:aabb::211:24ff:fe80:d01e"); // SetBGPNextIPaddress(&record, PF_INET6, "2004:234:aabb::211:24ff:fe80:d01e"); record.srcport = 1024; record.dstport = 25; record.tcp_flags = 27; record.dPkts = 10; record.dOctets = 15100; fprintf(stderr, "IPv6 32bit packets 32bit bytes\n"); UpdateRecord(&record); PackRecord(&record, nffile); SetIPaddress(&record, PF_INET6, "2001:234:aabb::211:24ff:fe80:d01e", "2001:620::8:203:baff:fe52:38e5"); record.srcport = 10240; record.dstport = 52345; record.dPkts = 10100; record.dOctets = 15000000; fprintf(stderr, "IPv6 32bit packets 32bit bytes\n"); UpdateRecord(&record); PackRecord(&record, nffile); record.dPkts = 10100000; record.dOctets = 0x100000000LL; fprintf(stderr, "IPv6 32bit packets 64bit bytes\n"); UpdateRecord(&record); PackRecord(&record, nffile); record.dPkts = 0x100000000LL; record.dOctets = 15000000; fprintf(stderr, "IPv6 64bit packets 32bit bytes\n"); UpdateRecord(&record); PackRecord(&record, nffile); record.dOctets = 0x200000000LL; fprintf(stderr, "IPv6 64bit packets 64bit bytes\n"); UpdateRecord(&record); PackRecord(&record, nffile); SetIPaddress(&record, PF_INET, "172.16.14.18", "192.168.170.113"); // SetNextIPaddress(&record, PF_INET, "172.72.1.2"); // SetBGPNextIPaddress(&record, PF_INET, "172.73.2.3"); record.srcport = 10240; record.dstport = 52345; record.dPkts = 10100000; record.dOctets = 0x100000000LL; fprintf(stderr, "IPv4 32bit packets 64bit bytes\n"); UpdateRecord(&record); PackRecord(&record, nffile); SetIPaddress(&record, PF_INET, "172.16.15.18", "192.168.170.114"); record.dPkts = 0x100000000LL; record.dOctets = 15000000; fprintf(stderr, "IPv4 64bit packets 32bit bytes\n"); UpdateRecord(&record); PackRecord(&record, nffile); SetIPaddress(&record, PF_INET, "172.16.16.18", "192.168.170.115"); record.dOctets = 0x200000000LL; fprintf(stderr, "IPv4 64bit packets 64bit bytes\n"); UpdateRecord(&record); PackRecord(&record, nffile); extension_info.map->ex_id[0] = EX_IO_SNMP_4; extension_info.map->extension_size = 0; i=0; while (extension_info.map->ex_id[i]) { int id = extension_info.map->ex_id[i]; extension_info.map->extension_size += extension_descriptor[id].size; i++; } memcpy(nffile->buff_ptr, (void *)extension_info.map, extension_info.map->size); nffile->buff_ptr += extension_info.map->size; nffile->block_header->NumRecords++; nffile->block_header->size += extension_info.map->size; UpdateRecord(&record); fprintf(stderr, "4 bytes interfaces, 2 bytes AS numbers %d %d\n", record.fwd_status, nffile->block_header->NumRecords); PackRecord(&record, nffile); extension_info.map->ex_id[0] = EX_IO_SNMP_2; extension_info.map->ex_id[1] = EX_AS_4; extension_info.map->extension_size = 0; i=0; while (extension_info.map->ex_id[i]) { int id = extension_info.map->ex_id[i]; extension_info.map->extension_size += extension_descriptor[id].size; i++; } memcpy(nffile->buff_ptr, (void *)extension_info.map, extension_info.map->size); nffile->buff_ptr += extension_info.map->size; nffile->block_header->NumRecords++; nffile->block_header->size += extension_info.map->size; UpdateRecord(&record); fprintf(stderr, "2 bytes interfaces, 4 bytes AS numbers %d %d\n", record.fwd_status, nffile->block_header->NumRecords); PackRecord(&record, nffile); extension_info.map->ex_id[0] = EX_IO_SNMP_4; extension_info.map->extension_size = 0; i=0; while (extension_info.map->ex_id[i]) { int id = extension_info.map->ex_id[i]; extension_info.map->extension_size += extension_descriptor[id].size; i++; } memcpy(nffile->buff_ptr, (void *)extension_info.map, extension_info.map->size); nffile->buff_ptr += extension_info.map->size; nffile->block_header->NumRecords++; nffile->block_header->size += extension_info.map->size; UpdateRecord(&record); fprintf(stderr, "4 bytes interfaces, 4 bytes AS numbers %d %d\n", record.fwd_status, nffile->block_header->NumRecords); PackRecord(&record, nffile); if ( nffile->block_header->NumRecords ) { if ( WriteBlock(nffile) <= 0 ) { fprintf(stderr, "Failed to write output buffer to disk: '%s'" , strerror(errno)); } } return 0; }
int RRD_StoreDataRow(char *path, char *iso_time, data_row *row) { char rrd_filename[1024], *buff, *s; char *rrd_arg[10]; time_t when, frag; int i, j, len, p, t, buffsize, argc; uint32_t pnum; struct stat statbuf; buffsize = MAXBUFF; buff = (char *)malloc(buffsize); if ( !buff ) { perror("Memory error!"); return 0; } when = ISO2UNIX(iso_time); if ( !when ) return 0; // make sure, we are at a 5min boundary frag = when % 300; if ( frag ) { fprintf(stderr, "Round to next timeslot: offset %lld\n", (long long)frag); when -= frag; } for ( p=tcp; p<=udp; p++ ) { // for every protocol TCP - UDP for ( t=flows; t<=bytes; t++ ) { // for every type flows - packets - bytes for (j=0; j<64; j++) { // for all 64 RRD files in proto - type len = snprintf(rrd_filename, 1024, "%s/%s-%s-%d.rrd", path, proto[p], type[t], j); if ( len >= 1024 ) { fprintf(stderr, "Failed to concat RRD filename: string overflow"); return 0; } // Check if RRD file exists if ( (stat(rrd_filename, &statbuf) < 0 ) || !(statbuf.st_mode & S_IFREG) ) { fprintf(stderr, "No such RRD file: '%s'\n", rrd_filename); return 0; } buffsize = MAXBUFF; s = buff; /* add time to RRD arg string */ len = snprintf(s, buffsize, "%lld:", (long long)when); buffsize -= len; s += len; /* add port data to RRD arg string */ for ( i=0; i<1024; i++) { pnum = ( j << 10 ) + i; /* if ( row[pnum].proto[p].type[t] ) { fprintf(stderr, "%d %d %d\n", pnum, p, t); } */ len = snprintf(s, buffsize, "%llu:", (long long unsigned)row[pnum].proto[p].type[t]); if ( len >= buffsize ) { fprintf(stderr, "No enough space to create RRD arg\n"); return 0; } buffsize -= len; s += len; } s--; *s = '\0'; // Create arg vector argc = 0; rrd_arg[argc++] = "update"; rrd_arg[argc++] = rrd_filename; rrd_arg[argc++] = buff; rrd_arg[argc] = NULL; optind = 0; opterr = 0; rrd_clear_error(); if ( ( i=rrd_update(argc, rrd_arg))) { fprintf(stderr, "RRD: %s Insert Error: %d %s\n", rrd_filename, i, rrd_get_error()); } } // for all 64 rrd files } // for every type flows - packets - bytes } // for every protocol TCP - UDP return 1; } // End of RRD_StoreDataRow
static void SetupProfileChannels(char *profile_datadir, char *profile_statdir, profile_param_info_t *profile_param, int subdir_index, char *filterfile, char *filename, int verify_only, int compress ) { FilterEngine_data_t *engine; struct stat stat_buf; char *p, *filter, *subdir, *wfile, *ofile, *rrdfile, *source_filter; char path[MAXPATHLEN]; int ffd, ret; size_t filter_size; nffile_t *nffile; ofile = wfile = NULL; nffile = NULL; /* * Compile the complete filter: * this consists of the source list and the filter stored in the file */ snprintf(path, MAXPATHLEN-1, "%s/%s/%s/%s-%s", profile_statdir, profile_param->profilegroup, profile_param->profilename, profile_param->channelname, filterfile); path[MAXPATHLEN-1] = '\0'; if ( stat(path, &stat_buf) || !S_ISREG(stat_buf.st_mode) ) { LogError("Skipping channel %s in profile '%s' group '%s'. No profile filter found.\n", profile_param->channelname, profile_param->profilename, profile_param->profilegroup); return; } // prepare source filter for this channel if ( profile_param->channel_sourcelist ) { // we have a channel_sourcelist: channel1|channel2|channel3 // source filter - therefore pattern is '( sourcefilter ) and ( filter )' // where sourcefilter is 'ident source1 or ident source2 ... ' char *q; size_t len = strlen(profile_param->channel_sourcelist); int num_sources = 1; // at least one source, otherwise we would not be in this code q = profile_param->channel_sourcelist; while ( (p = strchr(q, '|')) != NULL ) { num_sources++; q = p; q++; } // allocate a temp buffer for the source filter. // for each source add 'ident <source> or ', which makes 10 char per sources, including '()\0 and ' = 8 len += 10 * num_sources + 8; source_filter = (char *)malloc(len); if ( !source_filter ) { LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) ); exit(255); } source_filter[0] = '('; source_filter[1] = '\0'; len--; q = profile_param->channel_sourcelist; do { p = strchr(q, '|'); if (p) *p = '\0'; if ( !AppendString(source_filter, "ident ", &len) ) return; if ( !AppendString(source_filter, q, &len) ) return; if ( p ) { // there is another source waiting behind *p if ( !AppendString(source_filter, " or ", &len) ) return; q = p; q++; } } while (p); if ( !AppendString(source_filter, ") and (", &len) ) return; } else // no source filter - therefore pattern is '(' filter ')' source_filter = "("; filter_size = stat_buf.st_size + strlen(source_filter) + 2; // +2 : ')\0' at the end of the filter filter = (char *)malloc(filter_size); if ( !filter ) { LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) ); exit(255); } ffd = open(path, O_RDONLY); if ( ffd < 0 ) { LogError("Can't open file '%s' for reading: %s\n",path, strerror(errno) ); return; } strncpy(filter, source_filter, strlen(source_filter)); p = filter + strlen(source_filter); ret = read(ffd, (void *)p, stat_buf.st_size); if ( ret < 0 ) { LogError("Can't read from file '%s': %s\n",path, strerror(errno) ); close(ffd); return; } close(ffd); p[stat_buf.st_size] = ')'; p[stat_buf.st_size+1] = '\0'; // compile profile filter if ( verify_only ) printf("Check filter for channel %s in profile '%s' in group '%s': ", profile_param->channelname, profile_param->profilename, profile_param->profilegroup); engine = CompileFilter(filter); if ( !engine ) { printf("\n"); LogError("*** Compiling filter failed for channel %s in profile '%s' in group '%s'.", profile_param->channelname, profile_param->profilename, profile_param->profilegroup); LogError("*** File: %s", path); LogError("*** Error: %s\n", yyerror_buff); LogError("*** Failed Filter: %s", filter); free(filter); return; } free(filter); if ( verify_only ) { printf("ok.\n"); return; } // path to the channel // channel exists and is a directory - checked in ParseParams snprintf(path, MAXPATHLEN-1, "%s/%s/%s/%s", profile_datadir, profile_param->profilegroup, profile_param->profilename, profile_param->channelname); path[MAXPATHLEN-1] = '\0'; if ( chdir(path)) { LogError("Error can't chdir to '%s': %s", path, strerror(errno)); exit(255); } // check for subdir hierarchy subdir = NULL; if ( (profile_param->profiletype & 4) == 0 ) { // no shadow profile int is_alert = (profile_param->profiletype & 8) == 8; if ( !is_alert && subdir_index && strlen(filename) == 19 && (strncmp(filename, "nfcapd.", 7) == 0) ) { char *p = &filename[7]; // points to ISO timstamp in filename time_t t = ISO2UNIX(p); struct tm *t_tm = localtime(&t); char error[255]; subdir = GetSubDir(t_tm); if ( !subdir ) { // failed to generate subdir path - put flows into base directory LogError( "Failed to create subdir path!"); } if ( !SetupSubDir(path, subdir, error, 255) ) { LogError( "Failed to create subdir path: '%s'" , error); // nothing else need to be done, as subdir == NULL means put files into channel directory } } if ( is_alert ) { // alert snprintf(path, MAXPATHLEN, "%s/%s/%s/%s/%s", profile_datadir, profile_param->profilegroup, profile_param->profilename, profile_param->channelname, filename); } else { // prepare output file for profile types != shadow if ( subdir ) snprintf(path, MAXPATHLEN, "%s/%s/%s/%s/%s/%s", profile_datadir, profile_param->profilegroup, profile_param->profilename, profile_param->channelname, subdir, filename); else snprintf(path, MAXPATHLEN, "%s/%s/%s/%s/%s", profile_datadir, profile_param->profilegroup, profile_param->profilename, profile_param->channelname, filename); } path[MAXPATHLEN-1] = '\0'; wfile = strdup(path); // ofile: file while profiling snprintf(path, MAXPATHLEN, "%s/%s/%s/%s/nfprofile.%llu", profile_datadir, profile_param->profilegroup, profile_param->profilename, profile_param->channelname, (unsigned long long)getpid()); path[MAXPATHLEN-1] = '\0'; ofile = strdup(path); nffile = OpenNewFile(path, NULL, compress, 0, NULL); if ( !nffile ) { return; } } snprintf(path, MAXPATHLEN-1, "%s/%s/%s/%s.rrd", profile_statdir, profile_param->profilegroup, profile_param->profilename, profile_param->channelname); path[MAXPATHLEN-1] = '\0'; rrdfile = strdup(path); snprintf(path, MAXPATHLEN, "%s/%s/%s/%s", profile_datadir, profile_param->profilegroup, profile_param->profilename, profile_param->channelname ); path[MAXPATHLEN-1] = '\0'; // collect all channel info profile_channels = realloc(profile_channels, (num_channels+1) * sizeof(profile_channel_info_t) ); if ( !profile_channels ) { LogError("Memory allocation error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) ); exit(255); } memset(&profile_channels[num_channels], 0, sizeof(profile_channel_info_t)); profile_channels[num_channels].engine = engine; profile_channels[num_channels].group = profile_param->profilegroup; profile_channels[num_channels].profile = profile_param->profilename; profile_channels[num_channels].channel = profile_param->channelname; profile_channels[num_channels].wfile = wfile; profile_channels[num_channels].ofile = ofile; profile_channels[num_channels].rrdfile = rrdfile; profile_channels[num_channels].dirstat_path = strdup(path); profile_channels[num_channels].type = profile_param->profiletype; profile_channels[num_channels].nffile = nffile; memset((void *)&profile_channels[num_channels].stat_record, 0, sizeof(stat_record_t)); profile_channels[num_channels].stat_record.first_seen = 0x7fffffff; profile_channels[num_channels].stat_record.last_seen = 0; num_channels++; return; } // End of SetupProfileChannels
void ExpireProfile(channel_t *channel, dirstat_t *current_stat, uint64_t maxsize, uint64_t maxlife, uint32_t runtime ) { int size_done, lifetime_done, done; char *expire_timelimit = ""; time_t now = time(NULL); uint64_t sizelimit, num_expired; if ( !channel ) return; done = 0; SetupSignalHandler(); if ( maxlife ) { // time_t t_expire = now - maxlife; // build an appropriate string for comparing time_t t_watermark = now - (time_t)((maxlife * current_stat->low_water)/100); // printf("Expire files before %s", ctime(&t_expire)); expire_timelimit = strdup(UNIX2ISO(t_watermark)); // printf("down to %s", ctime(&t_watermark)); // printf("Diff: %i\n", t_watermark - t_expire ); } size_done = maxsize == 0 || current_stat->filesize < maxsize; sizelimit = (current_stat->low_water * maxsize)/100; lifetime_done = maxlife == 0 || ( now - current_stat->first ) < maxlife; num_expired = 0; PrepareDirLists(channel); if ( runtime ) alarm(runtime); while ( !done ) { char *p; int file_removed; // search for the channel with oldest file. If all channel have same age, // get the last in the list channel_t *expire_channel = channel; channel_t *compare_channel = expire_channel->next; while ( compare_channel ) { if ( expire_channel->ftsent == NULL ) { expire_channel = compare_channel; } if ( compare_channel->ftsent == NULL ) { compare_channel = compare_channel->next; continue; } // at this point expire_channel and current_channel fts entries are valid if ( strcmp(expire_channel->ftsent->fts_name, compare_channel->ftsent->fts_name) >= 0 ) { expire_channel = compare_channel; } compare_channel = compare_channel->next; } if ( !expire_channel->ftsent ) { // no more entries in any channel - we are done done = 1; continue; } // flag is file got removed file_removed = 0; // expire_channel now points to the channel with oldest file // do expire p = &(expire_channel->ftsent->fts_name[7]); // printf("File: %s\n", expire_channel->ftsent->fts_path); if ( !size_done ) { // expire size-wise if needed // printf(" Size expire %llu %llu\n", current_stat->filesize, sizelimit); if ( current_stat->filesize > sizelimit ) { // need to delete this file if ( unlink(expire_channel->ftsent->fts_path) == 0 ) { // Update profile stat current_stat->filesize -= 512 * expire_channel->ftsent->fts_statp->st_blocks; current_stat->numfiles--; // Update channel stat expire_channel->dirstat->filesize -= 512 * expire_channel->ftsent->fts_statp->st_blocks; expire_channel->dirstat->numfiles--; // decrement number of files seen in this directory expire_channel->ftsent->fts_number--; file_removed = 1; num_expired++; } else { LogError( "unlink() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) ); } } else { // we are done size-wise // time of first file not expired = start time of channel/profile expire_channel->dirstat->first = current_stat->first = ISO2UNIX(p); size_done = 1; } } else if ( !lifetime_done ) { // printf(" Time expire \n"); // expire time-wise if needed // this part of the code is executed only when size-wise is already fullfilled if ( strcmp(p, expire_timelimit) < 0 ) { // need to delete this file if ( unlink(expire_channel->ftsent->fts_path) == 0 ) { // Update profile stat current_stat->filesize -= 512 * expire_channel->ftsent->fts_statp->st_blocks; current_stat->numfiles--; // Update channel stat expire_channel->dirstat->filesize -= 512 * expire_channel->ftsent->fts_statp->st_blocks; expire_channel->dirstat->numfiles--; // decrement number of files seen in this directory expire_channel->ftsent->fts_number--; file_removed = 1; num_expired++; } else { LogError( "unlink() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) ); } } else { // we are done time-wise // time of first file not expired = start time of channel/profile expire_channel->dirstat->first = current_stat->first = ISO2UNIX(p); lifetime_done = 1; } } else // all done done = 1; if ( timeout ) done = 1; // advance fts entry in expire channel to next file, if file was removed if ( file_removed ) { expire_channel->ftsent = fts_read(expire_channel->fts); while ( expire_channel->ftsent ) { if ( expire_channel->ftsent->fts_info == FTS_F ) { // entry is a file expire_channel->ftsent->fts_number++; if ( expire_channel->ftsent->fts_namelen == 19 && strncmp(expire_channel->ftsent->fts_name, "nfcapd.", 7) == 0 ) { // if ftsent points to next valid file char *p = &(expire_channel->ftsent->fts_name[7]); // next file is first (oldest) for channel and for profile - update first mark expire_channel->dirstat->first = current_stat->first = ISO2UNIX(p); break; } } else { switch (expire_channel->ftsent->fts_info) { case FTS_D: // entry is a directory // set number of files seen in this directory = 0 expire_channel->ftsent->fts_number = 0; // skip all '.' entries as well as hidden directories if ( expire_channel->ftsent->fts_level > 0 && expire_channel->ftsent->fts_name[0] == '.' ) fts_set(expire_channel->fts, expire_channel->ftsent, FTS_SKIP); // any valid directory needs to start with a digit ( %Y -> year ) if ( expire_channel->ftsent->fts_level > 0 && !isdigit(expire_channel->ftsent->fts_name[0]) ) fts_set(expire_channel->fts, expire_channel->ftsent, FTS_SKIP); break; case FTS_DP: // do not delete base data directory ( level == 0 ) if ( expire_channel->ftsent->fts_number == 0 && expire_channel->ftsent->fts_level > 0 ) { // directory is empty and can be deleted // printf("Will remove directory %s\n", expire_channel->ftsent->fts_path); if ( rmdir(expire_channel->ftsent->fts_path) != 0 ) { LogError( "rmdir() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) ); } } break; } } // otherwise loop expire_channel->ftsent = fts_read(expire_channel->fts); } // end advance fts entry file_removed = 0; } if ( expire_channel->ftsent == NULL ) { // this channel has no more files now expire_channel->dirstat->first = expire_channel->dirstat->last; if ( expire_channel->dirstat->numfiles ) { // if channel is empty, no files must be reported, but rebuild is done anyway LogError( "Inconsitency detected in channel %s. Will rebuild automatically.\n", expire_channel->datadir); LogError( "No more files found, but %llu expected.\n", expire_channel->dirstat->numfiles); } expire_channel->dirstat->numfiles = 0; expire_channel->dirstat->status = FORCE_REBUILD; } } // while ( !done ) if ( runtime ) alarm(0); if ( timeout ) { LogError( "Maximum execution time reached! Interrupt expire.\n"); } } // End of ExpireProfile
void ExpireDir(char *dir, dirstat_t *dirstat, uint64_t maxsize, uint64_t maxlife, uint32_t runtime ) { FTS *fts; FTSENT *ftsent; uint64_t sizelimit, num_expired; int done, size_done, lifetime_done, dir_files; char *const path[] = { dir, NULL }; char *expire_timelimit = NULL; time_t now = time(NULL); dir_files = 0; if ( dirstat->low_water == 0 ) dirstat->low_water = 95; if ( runtime ) { SetupSignalHandler(); alarm(runtime); } if ( maxlife ) { // build an appropriate string for comparing time_t t_expire = now - maxlife; time_t t_watermark = now - (time_t)((maxlife * dirstat->low_water)/100); // printf("Expire files before %s", ctime(&t_expire)); expire_timelimit = strdup(UNIX2ISO(t_watermark)); // printf("down to %s", ctime(&t_watermark)); // printf("Diff: %i\n", t_watermark - t_expire ); if ( dirstat->last < t_expire && (isatty(STDIN_FILENO) ) ) { // this means all files will get expired - are you sure ? char *s, s1[32], s2[32]; time_t t; struct tm *when; t = t_expire; when = localtime(&t); strftime(s1, 31, "%Y-%m-%d %H:%M:%S", when); s1[31] = '\0'; t = dirstat->last; when = localtime(&t); strftime(s2, 31, "%Y-%m-%d %H:%M:%S", when); s2[31] = '\0'; printf("Your max lifetime of %s will expire all file before %s\n", ScaleTime(maxlife), s1); printf("Your latest files are dated %s. This means all files will be deleted!\n", s2); printf("Are you sure? yes/[no] "); s = fgets(s1, 31, stdin); s1[31] = '\0'; if ( s && strncasecmp(s1, "yes\n", 31) == 0 ) { printf("Ok - you've beeen warned!\n"); } else { printf("Expire canceled!\n"); return; } } } done = 0; size_done = maxsize == 0 || dirstat->filesize < maxsize; lifetime_done = maxlife == 0 || ( now - dirstat->first ) < maxlife; sizelimit = (dirstat->low_water * maxsize)/100; num_expired = 0; fts = fts_open(path, FTS_LOGICAL, compare); while ( !done && ((ftsent = fts_read(fts)) != NULL) ) { if ( ftsent->fts_info == FTS_F ) { dir_files++; // count files in directories if ( ftsent->fts_namelen == 19 && strncmp(ftsent->fts_name, "nfcapd.", 7) == 0 ) { // nfcapd.200604301200 strlen = 19 char *s, *p = &(ftsent->fts_name[7]); // process only nfcapd. files // make sure it's really an nfcapd. file and we have // only digits in the rest of the file name s = p; while ( *s ) { if ( *s < '0' || *s > '9' ) break; s++; } // otherwise skip if ( *s ) continue; // expire size-wise if needed if ( !size_done ) { if ( dirstat->filesize > sizelimit ) { if ( unlink(ftsent->fts_path) == 0 ) { dirstat->filesize -= 512 * ftsent->fts_statp->st_blocks; num_expired++; dir_files--; } else { LogError( "unlink() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) ); } continue; // next file if file was unlinked } else { dirstat->first = ISO2UNIX(p); // time of first file not expired size_done = 1; } } // expire time-wise if needed // this part of the code is executed only when size-wise is fullfilled if ( !lifetime_done ) { if ( expire_timelimit && strcmp(p, expire_timelimit) < 0 ) { if ( unlink(ftsent->fts_path) == 0 ) { dirstat->filesize -= 512 * ftsent->fts_statp->st_blocks; num_expired++; dir_files--; } else { LogError( "unlink() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) ); } lifetime_done = 0; } else { dirstat->first = ISO2UNIX(p); // time of first file not expired lifetime_done = 1; } } done = (size_done && lifetime_done) || timeout; } } else { switch (ftsent->fts_info) { case FTS_D: // set pre-order flag dir_files = 0; // skip all '.' entries as well as hidden directories if ( ftsent->fts_level > 0 && ftsent->fts_name[0] == '.' ) fts_set(fts, ftsent, FTS_SKIP); // any valid directory needs to start with a digit ( %Y -> year ) if ( ftsent->fts_level > 0 && !isdigit(ftsent->fts_name[0]) ) fts_set(fts, ftsent, FTS_SKIP); break; case FTS_DP: // do not delete base data directory ( level == 0 ) if ( dir_files == 0 && ftsent->fts_level > 0 ) { // directory is empty and can be deleted // printf("Will remove directory %s\n", ftsent->fts_path); if ( rmdir(ftsent->fts_path) != 0 ) { LogError( "rmdir() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) ); } } break; } } } fts_close(fts); if ( !done ) { // all files expired and limits not reached // this may be possible, when files get time-wise expired and // the time limit is shorter than the latest file dirstat->first = dirstat->last; } if ( runtime ) alarm(0); if ( timeout ) { LogError( "Maximum execution time reached! Interrupt expire.\n"); } if ( num_expired > dirstat->numfiles ) { LogError( "Error updating stat record: Number of files inconsistent!\n"); LogError( "Will automatically rebuild this directory next time\n"); dirstat->numfiles = 0; dirstat->status = FORCE_REBUILD; } else { dirstat->numfiles -= num_expired; } if ( dirstat->numfiles == 0 ) { dirstat->first = dirstat->last = time(NULL); dirstat->status = FORCE_REBUILD; } free(expire_timelimit); } // End of ExpireDir
void RescanDir(char *dir, dirstat_t *dirstat) { FTS *fts; FTSENT *ftsent; char *const path[] = { dir, NULL }; char first_timestring[16], last_timestring[16]; dirstat->filesize = dirstat->numfiles = 0; dirstat->first = 0; dirstat->last = 0; strncpy(first_timestring, "999999999999", 15); strncpy(last_timestring, "000000000000", 15); fts = fts_open(path, FTS_LOGICAL, compare); if ( !fts ) { LogError( "fts_open() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) ); return; } while ( (ftsent = fts_read(fts)) != NULL) { if ( ftsent->fts_info == FTS_F && ftsent->fts_namelen == 19 ) { // nfcapd.200604301200 strlen = 19 if ( strncmp(ftsent->fts_name, "nfcapd.", 7) == 0 ) { char *s, *p = &(ftsent->fts_name[7]); // make sure, we have only digits s = p; while ( *s ) { if ( *s < '0' || *s > '9' ) break; s++; } // otherwise skip if ( *s ) continue; if ( strcmp(p, first_timestring) < 0 ) { first_timestring[0] = '\0'; strncat(first_timestring, p, 15); } if ( strcmp(p, last_timestring) > 0 ) { last_timestring[0] = '\0'; strncat(last_timestring, p, 15); } dirstat->filesize += 512 * ftsent->fts_statp->st_blocks; dirstat->numfiles++; } } else { switch (ftsent->fts_info) { case FTS_D: // skip all '.' entries as well as hidden directories if ( ftsent->fts_level > 0 && ftsent->fts_name[0] == '.' ) fts_set(fts, ftsent, FTS_SKIP); // any valid dirctory need to start with a digit ( %Y -> year ) if ( ftsent->fts_level > 0 && !isdigit(ftsent->fts_name[0]) ) fts_set(fts, ftsent, FTS_SKIP); break; case FTS_DP: break; } } } fts_close(fts); // no files means do rebuild next time, otherwise the stat record may not be accurate if ( dirstat->numfiles == 0 ) { dirstat->first = dirstat->last = time(NULL); dirstat->status = FORCE_REBUILD; } else { dirstat->first = ISO2UNIX(first_timestring); dirstat->last = ISO2UNIX(last_timestring); dirstat->status = STATFILE_OK; } } // End of RescanDir
int main( int argc, char **argv ) { struct stat stat_buff; char c, *wfile, *rfile, *Rfile, *Mdirs, *ffile, *filter, *timeslot, *DBdir; char datestr[64]; int ffd, ret, DBinit, AddDB, GenStat, AvStat, output_mode; unsigned int lastupdate, topN; data_row *port_table; time_t when; struct tm * t1; wfile = rfile = Rfile = Mdirs = ffile = filter = DBdir = timeslot = NULL; DBinit = AddDB = GenStat = AvStat = 0; lastupdate = output_mode = 0; topN = 10; while ((c = getopt(argc, argv, "d:hln:pr:st:w:AIM:R:SV")) != EOF) { switch (c) { case 'h': usage(argv[0]); exit(0); break; case 'I': DBinit = 1; break; case 'M': Mdirs = strdup(optarg); break; case 'R': Rfile = strdup(optarg); break; case 'd': DBdir = strdup(optarg); ret = stat(DBdir, &stat_buff); if ( !(stat_buff.st_mode & S_IFDIR) ) { fprintf(stderr, "No such directory: %s\n", DBdir); exit(255); } break; case 'l': lastupdate = 1; break; case 'n': topN = atoi(optarg); if ( topN < 0 ) { fprintf(stderr, "TopnN number %i out of range\n", topN); exit(255); } break; case 'p': output_mode = 1; break; case 'r': rfile = strdup(optarg); break; case 'w': wfile = strdup(optarg); break; case 's': GenStat = 1; break; case 't': timeslot = optarg; if ( !ISO2UNIX(timeslot) ) { exit(255); } break; case 'A': AddDB = 1; break; case 'S': AvStat = 1; break; default: usage(argv[0]); exit(0); } } if (argc - optind > 1) { usage(argv[0]); exit(255); } else { /* user specified a pcap filter */ filter = argv[optind]; } openlog(argv[0] , LOG_CONS|LOG_PID, LOG_DAEMON); if ( !filter && ffile ) { if ( stat(ffile, &stat_buff) ) { perror("Can't stat file"); exit(255); } filter = (char *)malloc(stat_buff.st_size); if ( !filter ) { perror("Memory error"); exit(255); } ffd = open(ffile, O_RDONLY); if ( ffd < 0 ) { perror("Can't open file"); exit(255); } ret = read(ffd, (void *)filter, stat_buff.st_size); if ( ret < 0 ) { perror("Error reading file"); close(ffd); exit(255); } close(ffd); } if ( !DBdir ) { fprintf(stderr, "DB directory required\n"); exit(255); } InitStat(DBdir); if ( !filter ) filter = "any"; Engine = CompileFilter(filter); if ( !Engine ) exit(254); if ( DBinit ) { when = time(NULL); when -= ((when % 300) + 300); InitStatFile(when, NUM_AV_SLOTS); if ( !CreateRRDBs(DBdir, when) ) { fprintf(stderr, "Init DBs failed\n"); exit(255); } fprintf(stderr, "Port DBs initialized.\n"); exit(0); } if ( lastupdate ) { when = RRD_LastUpdate(DBdir); if ( !when ) exit(255); t1 = localtime(&when); strftime(datestr, 63, "%b %d %Y %T", t1); printf("Last Update: %i, %s\n", (int)when, datestr); exit(0); } port_table = NULL; if ( Mdirs || Rfile || rfile ) { SetupInputFileSequence(Mdirs, rfile, Rfile); port_table = process(filter); // Lister(port_table); if ( !port_table ) { exit(255); } if ( AddDB ) { if ( !timeslot ) { fprintf(stderr, "Timeslot required!\n"); exit(255); } UpdateStat(port_table, ISO2UNIX(timeslot)); RRD_StoreDataRow(DBdir, timeslot, port_table); } } if ( AvStat ) { port_table = GetStat(); if ( !port_table ) { fprintf(stderr, "Unable to get port table!\n"); exit(255); } // DoStat Generate_TopN(port_table, topN, NUM_AV_SLOTS, 0, output_mode, wfile); } if ( GenStat ) { when = ISO2UNIX(timeslot); if ( !port_table ) { if ( !timeslot ) { fprintf(stderr, "Timeslot required!\n"); exit(255); } port_table = RRD_GetDataRow(DBdir, when); } if ( !port_table ) { fprintf(stderr, "Unable to get port table!\n"); exit(255); } // DoStat Generate_TopN(port_table, topN, 1, when, output_mode, wfile); } CloseStat(); return 0; }