int StorePcapFlow(FlowSource_t *fs, struct FlowNode *Node) { common_record_t *common_record; uint32_t packets, bytes, pcap_output_record_size; uint64_t start_time, end_time; int j, id; char *string; void *data_ptr; if ( !pcap_extension_map ) { pcap_extension_map = (extension_map_t *)malloc(pcap_extension_info.map->size); if ( !pcap_extension_map ) { LogError("Process_pcap: malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno)); return 0; } memcpy((void *)pcap_extension_map, (void *)pcap_extension_info.map, pcap_extension_info.map->size); if ( !AddExtensionMap(fs, pcap_extension_map) ) { LogError("Process_pcap: Fatal: AddExtensionMap() failed in %s line %d\n", __FILE__, __LINE__); return 0; } } if ( Node->version == AF_INET6 ) { pcap_output_record_size = pcap_output_record_size_v6; dbg_printf("Store Flow v6 node: size: %u\n", pcap_output_record_size); } else if ( Node->version == AF_INET ) { pcap_output_record_size = pcap_output_record_size_v4; dbg_printf("Store Flow v4 node: size: %u\n", pcap_output_record_size); } else { LogError("Process_pcap: Unexpected version in %s line %d: %u\n", __FILE__, __LINE__, Node->version); return 0; } // output buffer size check for all expected records if ( !CheckBufferSpace(fs->nffile, pcap_output_record_size) ) { // fishy! - should never happen. maybe disk full? LogError("Process_pcap: output buffer size error. Abort pcap record processing"); return 0; } // map output record to memory buffer common_record = (common_record_t *)fs->nffile->buff_ptr; // header data common_record->flags = 0; common_record->type = CommonRecordType; common_record->exporter_sysid = 0; common_record->ext_map = pcap_extension_map->map_id; common_record->size = pcap_output_record_size; // pcap common fields common_record->srcport = Node->src_port; common_record->dstport = Node->dst_port; common_record->tcp_flags = Node->flags; common_record->prot = Node->proto; common_record->tos = 0; common_record->fwd_status = 0; if ( Node->version == AF_INET6 ) { SetFlag(common_record->flags, FLAG_IPV6_ADDR); pcap_v6_block_t *pcap_v6_block = (pcap_v6_block_t *)common_record->data; pcap_v6_block->srcaddr[0] = Node->src_addr.v6[0]; pcap_v6_block->srcaddr[1] = Node->src_addr.v6[1]; pcap_v6_block->dstaddr[0] = Node->dst_addr.v6[0]; pcap_v6_block->dstaddr[1] = Node->dst_addr.v6[1]; pcap_v6_block->dPkts = packets = Node->packets; pcap_v6_block->dOctets = bytes = Node->bytes; data_ptr = (void *)pcap_v6_block->data; } else { pcap_v4_block_t *pcap_v4_block = (pcap_v4_block_t *)common_record->data; pcap_v4_block->srcaddr = Node->src_addr.v4; pcap_v4_block->dstaddr = Node->dst_addr.v4; pcap_v4_block->dPkts = packets = Node->packets; pcap_v4_block->dOctets = bytes = Node->bytes; data_ptr = (void *)pcap_v4_block->data; } // process optional extensions j = 0; while ( (id = pcap_extension_map->ex_id[j]) != 0 ) { switch (id) { case EX_IO_SNMP_2: { // 2 byte input/output interface index tpl_ext_4_t *tpl = (tpl_ext_4_t *)data_ptr; tpl->input = 0; tpl->output = 0; data_ptr = (void *)tpl->data; } break; default: // this should never happen, as pcap has no other extensions LogError("Process_pcap: Unexpected extension %i for pcap record. Skip extension", id); } j++; } common_record->first = Node->t_first.tv_sec; common_record->msec_first = Node->t_first.tv_usec / 1000; common_record->last = Node->t_last.tv_sec; common_record->msec_last = Node->t_last.tv_usec / 1000; start_time = (1000LL * (uint64_t)common_record->first) + (uint64_t)common_record->msec_first; end_time = (1000LL * (uint64_t)common_record->last) + (uint64_t)common_record->msec_last; // update first_seen, last_seen if ( start_time < fs->first_seen ) fs->first_seen = start_time; if ( end_time > fs->last_seen ) fs->last_seen = end_time; // Update stats switch (common_record->prot) { case IPPROTO_ICMP: case IPPROTO_ICMPV6: fs->nffile->stat_record->numflows_icmp++; fs->nffile->stat_record->numpackets_icmp += packets; fs->nffile->stat_record->numbytes_icmp += bytes; // fix odd CISCO behaviour for ICMP port/type in src port if ( common_record->srcport != 0 ) { uint8_t *s1, *s2; s1 = (uint8_t *)&(common_record->srcport); s2 = (uint8_t *)&(common_record->dstport); s2[0] = s1[1]; s2[1] = s1[0]; common_record->srcport = 0; } break; case IPPROTO_TCP: fs->nffile->stat_record->numflows_tcp++; fs->nffile->stat_record->numpackets_tcp += packets; fs->nffile->stat_record->numbytes_tcp += bytes; break; case IPPROTO_UDP: fs->nffile->stat_record->numflows_udp++; fs->nffile->stat_record->numpackets_udp += packets; fs->nffile->stat_record->numbytes_udp += bytes; break; default: fs->nffile->stat_record->numflows_other++; fs->nffile->stat_record->numpackets_other += packets; fs->nffile->stat_record->numbytes_other += bytes; } fs->nffile->stat_record->numflows++; fs->nffile->stat_record->numpackets += packets; fs->nffile->stat_record->numbytes += bytes; if ( fs->xstat ) { uint32_t bpp = packets ? bytes/packets : 0; if ( bpp > MAX_BPP ) bpp = MAX_BPP; if ( common_record->prot == IPPROTO_TCP ) { fs->xstat->bpp_histogram->tcp.bpp[bpp]++; fs->xstat->bpp_histogram->tcp.count++; fs->xstat->port_histogram->src_tcp.port[common_record->srcport]++; fs->xstat->port_histogram->dst_tcp.port[common_record->dstport]++; fs->xstat->port_histogram->src_tcp.count++; fs->xstat->port_histogram->dst_tcp.count++; } else if ( common_record->prot == IPPROTO_UDP ) { fs->xstat->bpp_histogram->udp.bpp[bpp]++; fs->xstat->bpp_histogram->udp.count++; fs->xstat->port_histogram->src_udp.port[common_record->srcport]++; fs->xstat->port_histogram->dst_udp.port[common_record->dstport]++; fs->xstat->port_histogram->src_udp.count++; fs->xstat->port_histogram->dst_udp.count++; } } if ( verbose ) { master_record_t master_record; ExpandRecord_v2((common_record_t *)common_record, &pcap_extension_info, NULL, &master_record); format_file_block_record(&master_record, &string, 0); printf("%s\n", string); } // update file record size ( -> output buffer size ) fs->nffile->block_header->NumRecords += 1; fs->nffile->block_header->size += pcap_output_record_size; fs->nffile->buff_ptr = data_ptr; return 1; } /* End of StorePcapFlow */
int ExportFlowTable(nffile_t *nffile, int aggregate, int bidir, int date_sorted, extension_map_list_t *extension_map_list) { hash_FlowTable *FlowTable; FlowTableRecord_t *r; SortElement_t *SortList; master_record_t *aggr_record_mask; uint32_t i; uint32_t maxindex, c; #ifdef DEVEL char *string; #endif ExportExtensionMaps(aggregate, bidir, nffile, extension_map_list); ExportExporterList(nffile); aggr_record_mask = GetMasterAggregateMask(); FlowTable = GetFlowTable(); c = 0; maxindex = FlowTable->NumRecords; if ( date_sorted ) { // Sort records according the date SortList = (SortElement_t *)calloc(maxindex, sizeof(SortElement_t)); if ( !SortList ) { LogError("malloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror (errno)); return 0; } // preset SortList table - still unsorted for ( i=0; i<=FlowTable->IndexMask; i++ ) { r = FlowTable->bucket[i]; if ( !r ) continue; // foreach elem in this bucket while ( r ) { SortList[c].count = 1000LL * r->flowrecord.first + r->flowrecord.msec_first; // sort according the date SortList[c].record = (void *)r; c++; r = r->next; } } if ( c != maxindex ) { LogError("Abort: Mismatch %s line %d: %s\n", __FILE__, __LINE__, strerror (errno)); return 0; } if ( c >= 2 ) heapSort(SortList, c, 0); for ( i = 0; i < c; i++ ) { master_record_t *flow_record; common_record_t *raw_record; extension_info_t *extension_info; r = (FlowTableRecord_t *)(SortList[i].record); raw_record = &(r->flowrecord); extension_info = r->map_info_ref; flow_record = &(extension_info->master_record); ExpandRecord_v2( raw_record, extension_info, r->exp_ref, flow_record); flow_record->dPkts = r->counter[INPACKETS]; flow_record->dOctets = r->counter[INBYTES]; flow_record->out_pkts = r->counter[OUTPACKETS]; flow_record->out_bytes = r->counter[OUTBYTES]; flow_record->aggr_flows = r->counter[FLOWS]; // apply IP mask from aggregation, to provide a pretty output if ( FlowTable->has_masks ) { flow_record->V6.srcaddr[0] &= FlowTable->IPmask[0]; flow_record->V6.srcaddr[1] &= FlowTable->IPmask[1]; flow_record->V6.dstaddr[0] &= FlowTable->IPmask[2]; flow_record->V6.dstaddr[1] &= FlowTable->IPmask[3]; } if ( FlowTable->apply_netbits ) ApplyNetMaskBits(flow_record, FlowTable->apply_netbits); if ( aggr_record_mask ) { ApplyAggrMask(flow_record, aggr_record_mask); } // switch to output extension map flow_record->map_ref = extension_info->map; flow_record->ext_map = extension_info->map->map_id; PackRecord(flow_record, nffile); #ifdef DEVEL format_file_block_record((void *)flow_record, &string, 0); printf("%s\n", string); #endif // Update statistics UpdateStat(nffile->stat_record, flow_record); } } else { // print them as they came for ( i=0; i<=FlowTable->IndexMask; i++ ) { r = FlowTable->bucket[i]; while ( r ) { master_record_t *flow_record; common_record_t *raw_record; extension_info_t *extension_info; raw_record = &(r->flowrecord); extension_info = r->map_info_ref; flow_record = &(extension_info->master_record); ExpandRecord_v2( raw_record, extension_info, r->exp_ref, flow_record); flow_record->dPkts = r->counter[INPACKETS]; flow_record->dOctets = r->counter[INBYTES]; flow_record->out_pkts = r->counter[OUTPACKETS]; flow_record->out_bytes = r->counter[OUTBYTES]; flow_record->aggr_flows = r->counter[FLOWS]; // apply IP mask from aggregation, to provide a pretty output if ( FlowTable->has_masks ) { flow_record->V6.srcaddr[0] &= FlowTable->IPmask[0]; flow_record->V6.srcaddr[1] &= FlowTable->IPmask[1]; flow_record->V6.dstaddr[0] &= FlowTable->IPmask[2]; flow_record->V6.dstaddr[1] &= FlowTable->IPmask[3]; } if ( FlowTable->apply_netbits ) ApplyNetMaskBits(flow_record, FlowTable->apply_netbits); if ( aggr_record_mask ) { ApplyAggrMask(flow_record, aggr_record_mask); } // switch to output extension map flow_record->map_ref = extension_info->map; flow_record->ext_map = extension_info->map->map_id; PackRecord(flow_record, nffile); #ifdef DEVEL format_file_block_record((void *)flow_record, &string, 0); printf("%s\n", string); #endif // Update statistics UpdateStat(nffile->stat_record, flow_record); r = r->next; } } } if ( nffile->block_header->NumRecords ) { if ( WriteBlock(nffile) <= 0 ) { LogError("Failed to write output buffer to disk: '%s'" , strerror(errno)); return 0; } } return 1; } // End of ExportFlowTable
void Process_v1(void *in_buff, ssize_t in_buff_cnt, FlowSource_t *fs) { netflow_v1_header_t *v1_header; netflow_v1_record_t *v1_record; exporter_v1_t *exporter; extension_map_t *extension_map; common_record_t *common_record; uint64_t start_time, end_time, boot_time; uint32_t First, Last; uint16_t count; uint8_t flags; int i, done, flow_record_length; ssize_t size_left; char *string; // map v1 data structure to input buffer v1_header = (netflow_v1_header_t *)in_buff; exporter = GetExporter(fs, v1_header); if ( !exporter ) { syslog(LOG_ERR,"Process_v1: Exporter NULL: Abort v1 record processing"); return; } flags = 0; exporter->packets++; extension_map = exporter->extension_map; flow_record_length = NETFLOW_V1_RECORD_LENGTH; // this many data to process size_left = in_buff_cnt; common_record = fs->nffile->buff_ptr; done = 0; while ( !done ) { v1_block_t *v1_block; /* Process header */ // count check count = ntohs(v1_header->count); if ( count > NETFLOW_V1_MAX_RECORDS ) { syslog(LOG_ERR,"Process_v1: Unexpected record count in header: %i. Abort v1 record processing", count); fs->nffile->buff_ptr = (void *)common_record; return; } // input buffer size check for all expected records if ( size_left < ( NETFLOW_V1_HEADER_LENGTH + count * flow_record_length) ) { syslog(LOG_ERR,"Process_v1: Not enough data to process v1 record. Abort v1 record processing"); fs->nffile->buff_ptr = (void *)common_record; return; } // output buffer size check for all expected records if ( !CheckBufferSpace(fs->nffile, count * v1_output_record_size) ) { // fishy! - should never happen. maybe disk full? syslog(LOG_ERR,"Process_v1: output buffer size error. Abort v1 record processing"); return; } // map output record to memory buffer common_record = (common_record_t *)fs->nffile->buff_ptr; v1_block = (v1_block_t *)common_record->data; v1_header->SysUptime = ntohl(v1_header->SysUptime); v1_header->unix_secs = ntohl(v1_header->unix_secs); v1_header->unix_nsecs = ntohl(v1_header->unix_nsecs); /* calculate boot time in msec */ boot_time = ((uint64_t)(v1_header->unix_secs)*1000 + ((uint64_t)(v1_header->unix_nsecs) / 1000000) ) - (uint64_t)(v1_header->SysUptime); // process all records v1_record = (netflow_v1_record_t *)((pointer_addr_t)v1_header + NETFLOW_V1_HEADER_LENGTH); /* loop over each records associated with this header */ for (i = 0; i < count; i++) { pointer_addr_t bsize; void *data_ptr; uint8_t *s1, *s2; int j, id; // header data common_record->flags = flags; common_record->type = CommonRecordType; common_record->exporter_sysid = exporter->info.sysid; common_record->ext_map = extension_map->map_id; common_record->size = v1_output_record_size; // v1 common fields common_record->srcport = ntohs(v1_record->srcport); common_record->dstport = ntohs(v1_record->dstport); common_record->tcp_flags = v1_record->tcp_flags; common_record->prot = v1_record->prot; common_record->tos = v1_record->tos; common_record->fwd_status = 0; common_record->reserved = 0; // v1 typed data as fixed struct v1_block v1_block->srcaddr = ntohl(v1_record->srcaddr); v1_block->dstaddr = ntohl(v1_record->dstaddr); v1_block->dPkts = ntohl(v1_record->dPkts); v1_block->dOctets = ntohl(v1_record->dOctets); // process optional extensions data_ptr = (void *)v1_block->data; j = 0; while ( (id = extension_map->ex_id[j]) != 0 ) { switch (id) { case EX_IO_SNMP_2: { // 2 byte input/output interface index tpl_ext_4_t *tpl = (tpl_ext_4_t *)data_ptr; tpl->input = ntohs(v1_record->input); tpl->output = ntohs(v1_record->output); data_ptr = (void *)tpl->data; } break; case EX_NEXT_HOP_v4: { // IPv4 next hop tpl_ext_9_t *tpl = (tpl_ext_9_t *)data_ptr; tpl->nexthop = ntohl(v1_record->nexthop); data_ptr = (void *)tpl->data; } break; case EX_ROUTER_IP_v4: { // IPv4 router address tpl_ext_23_t *tpl = (tpl_ext_23_t *)data_ptr; tpl->router_ip = fs->ip.v4; data_ptr = (void *)tpl->data; ClearFlag(common_record->flags, FLAG_IPV6_EXP); } break; case EX_RECEIVED: { tpl_ext_27_t *tpl = (tpl_ext_27_t *)data_ptr; tpl->received = (uint64_t)((uint64_t)fs->received.tv_sec * 1000LL) + (uint64_t)((uint64_t)fs->received.tv_usec / 1000LL); data_ptr = (void *)tpl->data; } break; default: // this should never happen, as v1 has no other extensions syslog(LOG_ERR,"Process_v1: Unexpected extension %i for v1 record. Skip extension", id); } j++; } // Time issues First = ntohl(v1_record->First); Last = ntohl(v1_record->Last); if ( First > Last ) { /* First in msec, in case of msec overflow, between start and end */ start_time = boot_time - 0x100000000LL + (uint64_t)First; } else { start_time = boot_time + (uint64_t)First; } /* end time in msecs */ end_time = (uint64_t)Last + boot_time; // if overflow happened after flow ended but before got exported if ( Last > v1_header->SysUptime ) { start_time -= 0x100000000LL; end_time -= 0x100000000LL; } common_record->first = start_time/1000; common_record->msec_first = start_time - common_record->first*1000; common_record->last = end_time/1000; common_record->msec_last = end_time - common_record->last*1000; // update first_seen, last_seen if ( start_time < fs->first_seen ) fs->first_seen = start_time; if ( end_time > fs->last_seen ) fs->last_seen = end_time; // Update stats switch (common_record->prot) { case IPPROTO_ICMP: fs->nffile->stat_record->numflows_icmp++; fs->nffile->stat_record->numpackets_icmp += v1_block->dPkts; fs->nffile->stat_record->numbytes_icmp += v1_block->dOctets; // fix odd CISCO behaviour for ICMP port/type in src port if ( common_record->srcport != 0 ) { s1 = (uint8_t *)&(common_record->srcport); s2 = (uint8_t *)&(common_record->dstport); s2[0] = s1[1]; s2[1] = s1[0]; common_record->srcport = 0; } break; case IPPROTO_TCP: fs->nffile->stat_record->numflows_tcp++; fs->nffile->stat_record->numpackets_tcp += v1_block->dPkts; fs->nffile->stat_record->numbytes_tcp += v1_block->dOctets; break; case IPPROTO_UDP: fs->nffile->stat_record->numflows_udp++; fs->nffile->stat_record->numpackets_udp += v1_block->dPkts; fs->nffile->stat_record->numbytes_udp += v1_block->dOctets; break; default: fs->nffile->stat_record->numflows_other++; fs->nffile->stat_record->numpackets_other += v1_block->dPkts; fs->nffile->stat_record->numbytes_other += v1_block->dOctets; } exporter->flows++; fs->nffile->stat_record->numflows++; fs->nffile->stat_record->numpackets += v1_block->dPkts; fs->nffile->stat_record->numbytes += v1_block->dOctets; if ( fs->xstat ) { uint32_t bpp = v1_block->dPkts ? v1_block->dOctets/v1_block->dPkts : 0; if ( bpp > MAX_BPP ) bpp = MAX_BPP; if ( common_record->prot == IPPROTO_TCP ) { fs->xstat->bpp_histogram->tcp.bpp[bpp]++; fs->xstat->bpp_histogram->tcp.count++; fs->xstat->port_histogram->src_tcp.port[common_record->srcport]++; fs->xstat->port_histogram->dst_tcp.port[common_record->dstport]++; fs->xstat->port_histogram->src_tcp.count++; fs->xstat->port_histogram->dst_tcp.count++; } else if ( common_record->prot == IPPROTO_UDP ) { fs->xstat->bpp_histogram->udp.bpp[bpp]++; fs->xstat->bpp_histogram->udp.count++; fs->xstat->port_histogram->src_udp.port[common_record->srcport]++; fs->xstat->port_histogram->dst_udp.port[common_record->dstport]++; fs->xstat->port_histogram->src_udp.count++; fs->xstat->port_histogram->dst_udp.count++; } } if ( verbose ) { master_record_t master_record; ExpandRecord_v2((common_record_t *)common_record, &v1_extension_info, &(exporter->info), &master_record); format_file_block_record(&master_record, &string, 0); printf("%s\n", string); } // advance to next input flow record v1_record = (netflow_v1_record_t *)((pointer_addr_t)v1_record + flow_record_length); if ( ((pointer_addr_t)data_ptr - (pointer_addr_t)common_record) != v1_output_record_size ) { printf("Panic size check: ptr diff: %llu, record size: %u\n", (unsigned long long)((pointer_addr_t)data_ptr - (pointer_addr_t)common_record), v1_output_record_size ); abort(); } // advance to next output record common_record = (common_record_t *)data_ptr; v1_block = (v1_block_t *)common_record->data; // buffer size sanity check - should never happen, but check it anyway bsize = (pointer_addr_t)common_record - (pointer_addr_t)fs->nffile->block_header - sizeof(data_block_header_t); if ( bsize > BUFFSIZE ) { syslog(LOG_ERR,"### Software error ###: %s line %d", __FILE__, __LINE__); syslog(LOG_ERR,"Process_v1: Output buffer overflow! Flush buffer and skip records."); syslog(LOG_ERR,"Buffer size: size: %u, bsize: %llu > %u", fs->nffile->block_header->size, (unsigned long long)bsize, BUFFSIZE); // reset buffer fs->nffile->block_header->size = 0; fs->nffile->block_header->NumRecords = 0; fs->nffile->buff_ptr = (void *)((pointer_addr_t)fs->nffile->block_header + sizeof(data_block_header_t) ); return; } } // End of foreach v1 record // update file record size ( -> output buffer size ) fs->nffile->block_header->NumRecords += count; fs->nffile->block_header->size += count * v1_output_record_size; fs->nffile->buff_ptr = (void *)common_record; // still to go for this many input bytes size_left -= NETFLOW_V1_HEADER_LENGTH + count * flow_record_length; // next header v1_header = (netflow_v1_header_t *)v1_record; // should never be < 0 done = size_left <= 0; } // End of while !done return; } /* End of Process_v1 */
int flows2nfdump(struct ftio *ftio, char *wfile, int compress, extension_info_t *extension_info, int extended, uint32_t limitflows) { // required flow tools variables struct fttime ftt; struct fts3rec_offsets fo; struct ftver ftv; char *rec; // nfdump variables nffile_t *nffile; master_record_t record; char *s; uint32_t cnt; s = "flow-tools"; nffile = OpenNewFile( wfile , NULL, compress, 0, s); if ( !nffile ) { fprintf(stderr, "%s\n", s); return 1; } AppendToBuffer(nffile, (void *)extension_info->map, extension_info->map->size); ftio_get_ver(ftio, &ftv); fts3rec_compute_offsets(&fo, &ftv); memset((void *)&record, 0, sizeof(record)); record.map_ref = extension_info->map; record.type = CommonRecordType; record.exporter_sysid = 0; // only v4 addresses ClearFlag(record.flags, FLAG_IPV6_ADDR); cnt = 0; while ((rec = ftio_read(ftio))) { uint32_t when, unix_secs, unix_nsecs, sysUpTime; int i, id; unix_secs = *((uint32_t*)(rec+fo.unix_secs)); unix_nsecs = *((uint32_t*)(rec+fo.unix_nsecs)); sysUpTime = *((uint32_t*)(rec+fo.sysUpTime)); when = *((uint32_t*)(rec+fo.First)); ftt = ftltime(sysUpTime, unix_secs, unix_nsecs, when); record.first = ftt.secs; record.msec_first = ftt.msecs; when = *((uint32_t*)(rec+fo.Last)); ftt = ftltime(sysUpTime, unix_secs, unix_nsecs, when); record.last = ftt.secs; record.msec_last = ftt.msecs; record.v4.srcaddr = *((uint32_t*)(rec+fo.srcaddr)); record.v4.dstaddr = *((uint32_t*)(rec+fo.dstaddr)); record.srcport = *((uint16_t*)(rec+fo.srcport)); record.dstport = *((uint16_t*)(rec+fo.dstport)); record.prot = *((uint8_t*)(rec+fo.prot)); record.tcp_flags = *((uint8_t*)(rec+fo.tcp_flags)); record.tos = *((uint8_t*)(rec+fo.tos)); record.dOctets = *((uint32_t*)(rec+fo.dOctets)); record.dPkts = *((uint32_t*)(rec+fo.dPkts)); i = 0; while ( (id = extension_info->map->ex_id[i]) != 0 ) { switch (id) { case EX_IO_SNMP_2: record.input = *((uint16_t*)(rec+fo.input)); record.output = *((uint16_t*)(rec+fo.output)); break; case EX_AS_2: record.srcas = *((uint16_t*)(rec+fo.src_as)); record.dstas = *((uint16_t*)(rec+fo.dst_as)); break; case EX_MULIPLE: record.src_mask = *((uint8_t*)(rec+fo.src_mask)); record.dst_mask = *((uint8_t*)(rec+fo.dst_mask)); record.dir = 0; record.dst_tos = 0; break; case EX_ROUTER_IP_v4: record.ip_nexthop.v4 = *((uint32_t*)(rec+fo.peer_nexthop)); break; case EX_NEXT_HOP_v4: record.ip_router.v4 = *((uint32_t*)(rec+fo.router_sc)); break; case EX_ROUTER_ID: record.engine_type = *((uint8_t*)(rec+fo.engine_type)); record.engine_id = *((uint8_t*)(rec+fo.engine_id)); break; // default: Other extensions can not be sent with v5 } i++; } PackRecord(&record, nffile); if ( extended ) { char *string; format_file_block_record(&record, &string, 0); fprintf(stderr, "%s\n", string); } cnt++; if ( cnt == limitflows ) break; } /* while */ // write the last records in buffer if ( nffile->block_header->NumRecords ) { if ( WriteBlock(nffile) <= 0 ) { fprintf(stderr, "Failed to write output buffer: '%s'" , strerror(errno)); } } free((void *)extension_info->map); free((void *)extension_info); DisposeFile(nffile); return 0; } // End of flows2nfdump