/* * Copyright (c) 2017, Peter Haag * Copyright (c) 2016, Peter Haag * Copyright (c) 2014, Peter Haag * Copyright (c) 2012, Peter Haag * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 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. * * Neither the name of the author nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_STDINT_H #include #endif #ifndef DEVEL # define dbg_printf(...) /* printf(__VA_ARGS__) */ #else # define dbg_printf(...) printf(__VA_ARGS__) #endif #include "util.h" #include "nffile.h" #include "nfx.h" #include "nfnet.h" #include "bookkeeper.h" #include "collector.h" #include "exporter.h" #include "nf_common.h" #include "netflow_v1.h" #include "netflow_v5_v7.h" #include "netflow_v9.h" #include "ipfix.h" /* global */ generic_exporter_t **exporter_list; /* local variables */ #define MAX_EXPORTERS 65535 static generic_exporter_t *exporter_root; #include "nffile_inline.c" /* local prototypes */ /* functions */ int InitExporterList(void) { exporter_list = calloc(MAX_EXPORTERS, sizeof(generic_exporter_t *)); if ( !exporter_list ) { LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) ); return 0; } exporter_root = NULL; return 1; } // End of InitExporterList int AddExporterInfo(exporter_info_record_t *exporter_record) { uint32_t id = exporter_record->sysid; int i; char *p1, *p2; // sanity check if ( id >= MAX_EXPORTERS ) { LogError("Exporter id: %u out of range. Skip exporter", id); return 0; } if ( exporter_list[id] != NULL ) { // slot already taken - check if exporters are identical exporter_record->sysid = exporter_list[id]->info.sysid; if ( memcmp((void *)exporter_record, (void *)&(exporter_list[id]->info), sizeof(exporter_info_record_t)) == 0 ) { dbg_printf("Found identical exporter record at SysID: %i, Slot: %u\n", exporter_record->sysid, id); // we are done return 2; } else { // exporters not identical - move current slot int i; // search first emty slot at the top of the list for ( i = id+1; i < MAX_EXPORTERS && exporter_list[i] != NULL; i++ ) {;} if ( i >= MAX_EXPORTERS ) { // all slots taken LogError("Too many exporters (>256)\n"); return 0; } dbg_printf("Move existing exporter from slot %u, to %i\n", id, i); // else - move slot exporter_list[i] = exporter_list[id]; exporter_list[id] = NULL; exporter_record->sysid = i; } } // slot[id] is now available exporter_list[id] = (generic_exporter_t *)calloc(1, sizeof(generic_exporter_t)); if ( !exporter_list[id] ) { LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) ); return 0; } // SPARC gcc fails here, if we use directly a pointer to the struct. // SPARC barfs and core dumps otherwise // memcpy((void *)&(exporter_list[id]->info), (void *)exporter_record, sizeof(exporter_info_record_t)); p1 = (char *)&(exporter_list[id]->info); p2 = (char *)exporter_record; for ( i=0; isysid); #ifdef DEVEL { #define IP_STRING_LEN 40 char ipstr[IP_STRING_LEN]; if ( exporter_record->sa_family == AF_INET ) { uint32_t _ip = htonl(exporter_record->ip.V4); inet_ntop(AF_INET, &_ip, ipstr, sizeof(ipstr)); printf("SysID: %u, IP: %16s, version: %u, ID: %2u, Slot: %u\n", exporter_record->sysid, ipstr, exporter_record->version, exporter_record->id, id); } else if ( exporter_record->sa_family == AF_INET6 ) { uint64_t _ip[2]; _ip[0] = htonll(exporter_record->ip.V6[0]); _ip[1] = htonll(exporter_record->ip.V6[1]); inet_ntop(AF_INET6, &_ip, ipstr, sizeof(ipstr)); printf("SysID: %u, IP: %40s, version: %u, ID: %2u, Slot: %u\n", exporter_record->sysid, ipstr, exporter_record->version, exporter_record->id, id); } else { strncpy(ipstr, "", IP_STRING_LEN); printf("**** Exporter IP version unknown ****\n"); } } printf("\n"); #endif if ( !exporter_root ) { exporter_root = exporter_list[id]; } return 1; } // End of AddExporterInfo int AddSamplerInfo(sampler_info_record_t *sampler_record) { uint32_t id = sampler_record->exporter_sysid; generic_sampler_t **sampler; if ( !exporter_list[id] ) { LogError("Exporter SysID: %u not found! - Skip sampler record", id); return 0; } sampler = &exporter_list[id]->sampler; while ( *sampler ) { if ( memcmp((void *)&(*sampler)->info, (void *)sampler_record, sizeof(sampler_info_record_t)) == 0 ) { // Found identical sampler already registered dbg_printf("Identical sampler already registered: Exporter SysID: %u, Sampler: id: %i, mode: %u, interval: %u\n", sampler_record->exporter_sysid, sampler_record->id, sampler_record->mode, sampler_record->interval); return 2; } sampler = &((*sampler)->next); } *sampler = (generic_sampler_t *)malloc(sizeof(generic_sampler_t)); if ( !*sampler ) { LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) ); return 0; } (*sampler)->next = NULL; sampler_record->exporter_sysid = exporter_list[id]->info.sysid; memcpy((void *)&(*sampler)->info, (void *)sampler_record, sizeof(sampler_info_record_t)); dbg_printf("Insert sampler record for exporter at slot %i:\n", id); #ifdef DEVEL { if ( sampler_record->id < 0 ) { printf("Exporter SysID: %u, Generic Sampler: mode: %u, interval: %u\n", sampler_record->exporter_sysid, sampler_record->mode, sampler_record->interval); } else { printf("Exporter SysID: %u, Sampler: id: %i, mode: %u, interval: %u\n", sampler_record->exporter_sysid, sampler_record->id, sampler_record->mode, sampler_record->interval); } } #endif return 1; } // End of AddSamplerInfo int AddExporterStat(exporter_stats_record_t *stat_record) { int i, use_copy; exporter_stats_record_t *rec; // 64bit counters can be potentially unaligned if ( ((ptrdiff_t)stat_record & 0x7) != 0 ) { rec = malloc(stat_record->header.size); if ( !rec ) { LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) ); exit(255); } memcpy(rec, stat_record, stat_record->header.size); use_copy = 1; } else { rec = stat_record; use_copy = 0; } for (i=0; istat_count; i++ ) { uint32_t id = rec->stat[i].sysid; if ( !exporter_list[id] ) { LogError("Exporter SysID: %u not found! - Skip stat record record.\n"); continue; } exporter_list[id]->sequence_failure += rec->stat[i].sequence_failure; exporter_list[id]->packets += rec->stat[i].packets; exporter_list[id]->flows += rec->stat[i].flows; dbg_printf("Update exporter stat for SysID: %i: Sequence failures: %u, packets: %llu, flows: %llu\n", id, exporter_list[id]->sequence_failure, exporter_list[id]->packets, exporter_list[id]->flows); } if ( use_copy ) free(rec); return 1; } // End of AddExporterStat void ExportExporterList( nffile_t *nffile ) { int i; // sysid 0 unused -> no exporter available i = 1; while ( i < MAX_EXPORTERS && exporter_list[i] != NULL ) { exporter_info_record_t *exporter; generic_sampler_t *sampler; exporter = &exporter_list[i]->info; AppendToBuffer(nffile, (void *)exporter, exporter->header.size); sampler = exporter_list[i]->sampler; while ( sampler ) { AppendToBuffer(nffile, (void *)&(sampler->info), sampler->info.header.size); sampler = sampler->next; } i++; } } // End of ExportExporterList void PrintExporters(char *filename) { int i, done, found = 0; nffile_t *nffile; record_header_t *record; uint32_t skipped_blocks; uint64_t total_bytes; printf("Exporters:\n"); nffile = OpenFile(filename, NULL); if ( !nffile ) { return; } total_bytes = 0; skipped_blocks = 0; done = 0; while ( !done ) { int i, ret; // get next data block from file ret = ReadBlock(nffile); switch (ret) { case NF_CORRUPT: case NF_ERROR: if ( ret == NF_CORRUPT ) LogError("Corrupt data file '%s': '%s'\n",filename); else LogError("Read error in file '%s': %s\n",filename, strerror(errno) ); done = 1; continue; break; // fall through - get next file in chain case NF_EOF: done = 1; continue; break; default: // successfully read block total_bytes += ret; } if ( nffile->block_header->id != DATA_BLOCK_TYPE_2 ) { skipped_blocks++; continue; } // block type = 2 record = (record_header_t *)nffile->buff_ptr; for ( i=0; i < nffile->block_header->NumRecords; i++ ) { switch ( record->type ) { // ExporterRecordType and SamplerRecordype tc versions only case ExporterRecordType: { #define IP_STRING_LEN 40 char ipstr[IP_STRING_LEN]; exporter_record_t *exporter_record = (exporter_record_t *)record ; found = 1; printf("\n"); if ( exporter_record->sa_family == AF_INET ) { uint32_t _ip = htonl(exporter_record->ip.V4); inet_ntop(AF_INET, &_ip, ipstr, sizeof(ipstr)); printf("SysID: %u, IP: %16s, version: %u, ID: %2u, Sequence Failures: %u\n", exporter_record->sysid, ipstr, exporter_record->version, exporter_record->exporter_id, exporter_record->sequence_failure); } else if ( exporter_record->sa_family == AF_INET6 ) { uint64_t _ip[2]; _ip[0] = htonll(exporter_record->ip.V6[0]); _ip[1] = htonll(exporter_record->ip.V6[1]); inet_ntop(AF_INET6, &_ip, ipstr, sizeof(ipstr)); printf("SysID: %u, IP: %40s, version: %u, ID: %2u, Sequence Failures: %u\n", exporter_record->sysid, ipstr, exporter_record->version, exporter_record->exporter_id, exporter_record->sequence_failure); } else { strncpy(ipstr, "", IP_STRING_LEN); printf("**** Exporter IP version unknown ****\n"); } } break; case SamplerRecordype: { sampler_record_t *sampler_record = (sampler_record_t *)record;; if ( sampler_record->id < 0 ) { printf(" Generic Sampler: mode: %u, interval: %u\n", sampler_record->mode, sampler_record->interval); } else { printf(" Sampler: id: %i, mode: %u, interval: %u\n", sampler_record->id, sampler_record->mode, sampler_record->interval); } } break; case ExporterInfoRecordType: found = 1; if ( !AddExporterInfo((exporter_info_record_t *)record) ) { LogError("Failed to add Exporter Record\n"); } break; case ExporterStatRecordType: AddExporterStat((exporter_stats_record_t *)record); break; case SamplerInfoRecordype: if ( !AddSamplerInfo((sampler_info_record_t *)record) ) { LogError("Failed to add Sampler Record\n"); } break; } // Advance pointer by number of bytes for netflow record record = (record_header_t *)((pointer_addr_t)record + record->size); } } CloseFile(nffile); DisposeFile(nffile); if ( !found ) { printf("No Exporter records found\n"); } i = 1; while ( i < MAX_EXPORTERS && exporter_list[i] != NULL ) { #define IP_STRING_LEN 40 char ipstr[IP_STRING_LEN]; exporter_info_record_t *exporter; generic_sampler_t *sampler; printf("\n"); exporter = &exporter_list[i]->info; if ( exporter->sa_family == AF_INET ) { uint32_t _ip = htonl(exporter->ip.V4); inet_ntop(AF_INET, &_ip, ipstr, sizeof(ipstr)); if ( exporter_list[i]->flows ) printf("SysID: %u, IP: %16s, version: %u, ID: %2u, Sequence failures: %u, packets: %llu, flows: %llu\n", exporter->sysid, ipstr, exporter->version, exporter->id, exporter_list[i]->sequence_failure, (long long unsigned)exporter_list[i]->packets, (long long unsigned)exporter_list[i]->flows); else printf("SysID: %u, IP: %16s, version: %u, ID: %2u\n", exporter->sysid, ipstr, exporter->version, exporter->id); } else if ( exporter->sa_family == AF_INET6 ) { uint64_t _ip[2]; _ip[0] = htonll(exporter->ip.V6[0]); _ip[1] = htonll(exporter->ip.V6[1]); inet_ntop(AF_INET6, &_ip, ipstr, sizeof(ipstr)); if ( exporter_list[i]->flows ) printf("SysID: %u, IP: %40s, version: %u, ID: %2u, Sequence failures: %u, packets: %llu, flows: %llu\n ", exporter->sysid, ipstr, exporter->version, exporter->id, exporter_list[i]->sequence_failure, (long long unsigned)exporter_list[i]->packets, (long long unsigned)exporter_list[i]->flows); else printf("SysID: %u, IP: %40s, version: %u, ID: %2u\n ", exporter->sysid, ipstr, exporter->version, exporter->id); } else { strncpy(ipstr, "", IP_STRING_LEN); printf("**** Exporter IP version unknown ****\n"); } sampler = exporter_list[i]->sampler; while ( sampler ) { if ( sampler->info.id < 0 ) { printf(" Sampler for Exporter SysID: %u, Generic Sampler: mode: %u, interval: %u\n", sampler->info.exporter_sysid, sampler->info.mode, sampler->info.interval); } else { printf(" Sampler for Exporter SysID: %u, Sampler: id: %i, mode: %u, interval: %u\n", sampler->info.exporter_sysid, sampler->info.id, sampler->info.mode, sampler->info.interval); } sampler = sampler->next; } i++; } } // End of PrintExporters