#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "libnf.h"
#include "bit_array.h"
#define MATH_INT64_NATIVE_IF_AVAILABLE 1
#include "../perl_math_int64.h"
#include "config.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/resource.h>
#include <netinet/in.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include "nffile.h"
#include "nfx.h"
#include "nfnet.h"
#include "bookkeeper.h"
#include "nfxstat.h"
#include "nf_common.h"
#include "rbtree.h"
#include "nftree.h"
#include "nfprof.h"
#include "nfdump.h"
#include "nflowcache.h"
#include "nfstat.h"
#include "nfexport.h"
#include "ipconv.h"
#include "util.h"
#include "flist.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <errno.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
/* Ignore Math-Int64 on 64 bit platform */
/* #define MATH_INT64_NATIVE 1 */
#if MATH_INT64_NATIVE
#undef newSVu64
#define newSVu64 newSVuv
#undef SvU64
#define SvU64 SvUV
#endif
/* defining macros for storing numbers, 64 bit numbers and strings into hash */
#define HV_STORE_NV(r,k,v) (void)hv_store(r, k, strlen(k), newSVnv(v), 0)
#define HV_STORE_U64V(r,k,v) (void)hv_store(r, k, strlen(k), newSVu64(v), 0)
#define HV_STORE_PV(r,k,v) (void)hv_store(r, k, strlen(k), newSVpvn(v, strlen(v)), 0)
/* hash parameters */
//#define NumPrealloc 128000
//#define AGGR_SIZE 7
//#define STRINGSIZE 10240
//static char data_string[STRINGSIZE];
/* list of maps used in file taht we create */
typedef struct libnf_file_list_s {
char *filename;
struct libnf_file_list_s *next;
} libnf_file_list_t;
/* list of maps used in file taht we create */
typedef struct libnf_map_list_s {
bit_array_t bit_array;
extension_map_t *map;
struct libnf_map_list_s *next;
} libnf_map_list_t;
/* structure that bears all data related to one instance */
typedef struct libnf_instance_s {
extension_map_list_t extension_map_list; /* nfdup structure containig extmap */
libnf_map_list_t *map_list; /* libnf structure that holds maps */
int max_num_extensions; /* mamimum number of extensions */
libnf_file_list_t *files; /* list of files to read */
nffile_t *nffile_r; /* filehandle to the file that we read data from */
nffile_t *nffile_w; /* filehandle for writing */
int blk_record_remains; /* counter of processed rows in a signle block */
FilterEngine_data_t *engine;
common_record_t *flow_record;
int *field_list;
int field_last;
// stat_record_t stat_record;
uint64_t processed_bytes; /* read statistics */
uint64_t total_files;
uint64_t processed_files;
uint64_t processed_blocks;
uint64_t skipped_blocks;
uint64_t processed_records;
char *current_filename; /* currently processed file name */
uint64_t current_processed_blocks;
// uint32_t is_anonymized;
time_t t_first_flow, t_last_flow;
time_t twin_start, twin_end;
master_record_t *master_record_r; /* pointer to last read master record */
master_record_t master_record_w; /* pointer to master record that will be stored */
bit_array_t ext_r; /* extension bit array for read and write */
bit_array_t ext_w;
} libnf_instance_t;
/* array of initalized instances */
libnf_instance_t *libnf_instances[NFL_MAX_INSTANCES] = { NULL };
/* Global Variables */
extern extension_descriptor_t extension_descriptor[];
// compare at most 16 chars
#define MAXMODELEN 16
#define STRINGSIZE 10240
#define IP_STRING_LEN (INET6_ADDRSTRLEN)
#include "nfdump_inline.c"
#include "nffile_inline.c"
//#include "nf_common.c"
/***********************************************************************
* *
* functions and macros for converting data types to perl's SV and back *
* *
************************************************************************/
/* cinverts unsigned integer 32b. to SV */
static inline SV * uint_to_SV(uint32_t n, int is_defined) {
if (!is_defined)
return newSV(0);
return newSVuv(n);
}
/* converts unsigned integer 64b. to SV */
static inline SV * uint64_to_SV(uint64_t n, int is_defined) {
if (!is_defined)
return newSV(0);
return newSVu64(n);
}
/* converts mpls array to SV */
static inline SV * mpls_to_SV(char *mpls, int is_defined) {
if (!is_defined)
return newSV(0);
return newSVpvn(mpls, sizeof(((struct master_record_s *)0)->mpls_label));
}
/* converts SV to MPLS string */
/* returns 0 if conversion was not succesfull */
static inline int SV_to_mpls(char *a, SV * sv) {
STRLEN len;
char *s;
s = SvPV(sv, len);
if ( len != sizeof(((struct master_record_s *)0)->mpls_label) )
return -1;
memcpy(a, s, sizeof(((struct master_record_s *)0)->mpls_label) );
return 0;
}
/* IPv4 or IPv6 address to SV */
static inline SV * ip_addr_to_SV(ip_addr_t *a, int is6, int is_defined) {
char s[IP_STRING_LEN];
int len = 0;
if (!is_defined)
return newSV(0);
if ( is6 ) { // IPv6
uint64_t ip[2];
ip[0] = htonll(a->v6[0]);
ip[1] = htonll(a->v6[1]);
len = sizeof(a->v6);
memcpy(s, ip, len);
} else { // IPv4
uint32_t ip;
//ip = a->v4;
ip = htonl(a->v4);
len = sizeof(a->v4);
memcpy(s, &ip, len);
}
return newSVpvn(s, len);
}
/* converts SV to IP addres (ip_addr_t) */
/* returns AF_INET or AF_INET6 based of the address type */
static inline int SV_to_ip_addr(ip_addr_t *a, SV * sv) {
uint64_t ip6[2];
uint32_t ip4;
char *s;
STRLEN len;
s = SvPV(sv, len);
if ( len == sizeof(ip4) ) {
memcpy(&ip4, s, sizeof(ip4));
//a->v4 = ip4;
a->v4 = ntohl(ip4);
return AF_INET;
} else if ( len == sizeof(ip6) ) {
memcpy(ip6, s, sizeof(ip6));
a->v6[0] = ntohll(ip6[0]);
a->v6[1] = ntohll(ip6[1]);
return AF_INET6;
} else {
return -1;
}
}
/* converts MAC address to SV */
static inline SV * mac_to_SV(uint8_t *a, int is_defined) {
char s[sizeof(uint64_t)];
int i;
if (!is_defined)
return newSV(0);
s[0] = 0;
for ( i=0; i<6; i++ ) {
s[5 - i] = a[i] & 0xFF;
}
return newSVpvn(s, 6);
}
/* converts SV to MAC addres and store to uint64_t */
/* returns 0 if conversion was not succesfull */
static inline int SV_to_mac(uint64_t *a, SV * sv) {
uint8_t *mac = (uint8_t *)a;
char *s;
int i;
STRLEN len;
s = SvPV(sv, len);
if ( len != 6 )
return -1;
for (i = 0; i < 6; i++) {
mac[5 - i] = s[i];
}
mac[6] = 0x0;
mac[7] = 0x0;
return 0;
}
/*
************************************************************************
* *
* end of convertion functions *
* *
************************************************************************
*/
/* returns the information about file get from file header */
SV * libnf_file_info(char *file) {
HV *res;
nffile_t *nffile = NULL;
res = (HV *)sv_2mortal((SV *)newHV());
nffile = OpenFile((char *)file, nffile);
if ( nffile == NULL ) {
return NULL;
}
HV_STORE_NV(res, "version", nffile->file_header->version);
HV_STORE_NV(res, "blocks", nffile->file_header->NumBlocks);
HV_STORE_NV(res, "compressed", nffile->file_header->flags & FLAG_COMPRESSED);
HV_STORE_NV(res, "anonymized", nffile->file_header->flags & FLAG_ANONYMIZED);
HV_STORE_NV(res, "catalog", nffile->file_header->flags & FLAG_CATALOG);
HV_STORE_PV(res, "ident", nffile->file_header->ident);
if (nffile->stat_record != NULL) {
HV_STORE_U64V(res, "flows", nffile->stat_record->numflows);
HV_STORE_U64V(res, "bytes", nffile->stat_record->numbytes);
HV_STORE_U64V(res, "packets", nffile->stat_record->numpackets);
HV_STORE_U64V(res, "flows_tcp", nffile->stat_record->numflows_tcp);
HV_STORE_U64V(res, "bytes_tcp", nffile->stat_record->numbytes_tcp);
HV_STORE_U64V(res, "packets_tcp", nffile->stat_record->numpackets_tcp);
HV_STORE_U64V(res, "flows_udp", nffile->stat_record->numflows_udp);
HV_STORE_U64V(res, "bytes_udp", nffile->stat_record->numbytes_udp);
HV_STORE_U64V(res, "packets_udp", nffile->stat_record->numpackets_udp);
HV_STORE_U64V(res, "flows_icmp", nffile->stat_record->numflows_icmp);
HV_STORE_U64V(res, "bytes_icmp", nffile->stat_record->numbytes_icmp);
HV_STORE_U64V(res, "packets_icmp", nffile->stat_record->numpackets_icmp);
HV_STORE_U64V(res, "flows_other", nffile->stat_record->numflows_other);
HV_STORE_U64V(res, "bytes_other", nffile->stat_record->numbytes_other);
HV_STORE_U64V(res, "packets_other", nffile->stat_record->numpackets_other);
HV_STORE_U64V(res, "first", nffile->stat_record->first_seen * 1000LL + nffile->stat_record->msec_first);
HV_STORE_U64V(res, "last", nffile->stat_record->last_seen * 1000LL + nffile->stat_record->msec_last);
// HV_STORE_NV(res, "msec_first", nffile->stat_record->msec_first);
// HV_STORE_NV(res, "msec_last", nffile->stat_record->msec_last);
HV_STORE_U64V(res, "sequence_failures", nffile->stat_record->sequence_failure);
}
CloseFile(nffile);
DisposeFile(nffile);
return newRV((SV *)res);
}
/* returns the information about instance */
SV * libnf_instance_info(int handle) {
libnf_instance_t *instance = libnf_instances[handle];
HV *res;
if (instance == NULL ) {
croak("%s handler %d not initialized", NFL_LOG);
return 0;
}
res = (HV *)sv_2mortal((SV *)newHV());
if ( instance->current_filename != NULL && instance->nffile_r != NULL ) {
int nblocs = instance->nffile_r->file_header->NumBlocks;
HV_STORE_PV(res, "current_filename", instance->current_filename);
HV_STORE_NV(res, "current_processed_blocks", instance->current_processed_blocks);
HV_STORE_NV(res, "current_total_blocks", nblocs);
}
HV_STORE_NV(res, "total_files", instance->total_files);
HV_STORE_NV(res, "processed_files", instance->processed_files);
HV_STORE_NV(res, "processed_blocks", instance->processed_blocks);
HV_STORE_NV(res, "processed_bytes", instance->processed_bytes);
HV_STORE_NV(res, "processed_records", instance->processed_records);
return newRV((SV *)res);
}
/* converts master_record to perl structures (hashref) */
/* TAG for check_items_map.pl: libnf_master_record_to_SV */
SV * libnf_master_record_to_AV(int handle, master_record_t *rec, extension_map_t *map) {
libnf_instance_t *instance = libnf_instances[handle];
AV *res_array;
//bit_array_t ext;
int i=0;
uint64_t t;
if (instance == NULL ) {
croak("%s handler %d not initialized", NFL_LOG);
return 0;
}
// processing map
bit_array_clear(&instance->ext_r);
i = 0;
while (map->ex_id[i]) {
bit_array_set(&instance->ext_r, map->ex_id[i], 1);
i++;
}
res_array = (AV *)sv_2mortal((SV *)newAV());
i = 0;
while ( instance->field_list[i] ) {
SV * sv;
switch ( instance->field_list[i] ) {
case NFL_I_FIRST:
t = rec->first * 1000LL + rec->msec_first;
sv = uint64_to_SV(t, 1);
break;
case NFL_I_LAST:
t = rec->last * 1000LL + rec->msec_last;
sv = uint64_to_SV(t, 1);
break;
case NFL_I_RECEIVED:
sv = uint64_to_SV(rec->received,
bit_array_get(&instance->ext_r, EX_RECEIVED) );
break;
case NFL_I_DPKTS:
sv = uint64_to_SV(rec->dPkts, 1);
break;
case NFL_I_DOCTETS:
sv = uint64_to_SV(rec->dOctets, 1);
break;
case NFL_I_OUT_PKTS:
sv = uint64_to_SV(rec->out_pkts,
bit_array_get(&instance->ext_r, EX_OUT_PKG_4) ||
bit_array_get(&instance->ext_r, EX_OUT_PKG_8) );
break;
case NFL_I_OUT_BYTES:
sv = uint64_to_SV(rec->out_bytes,
bit_array_get(&instance->ext_r, EX_OUT_BYTES_4) ||
bit_array_get(&instance->ext_r, EX_OUT_BYTES_8) );
break;
case NFL_I_AGGR_FLOWS:
sv = uint64_to_SV(rec->aggr_flows,
bit_array_get(&instance->ext_r, EX_AGGR_FLOWS_4) ||
bit_array_get(&instance->ext_r, EX_AGGR_FLOWS_8) );
break;
case NFL_I_SRCPORT:
sv = uint_to_SV(rec->srcport, 1);
break;
case NFL_I_DSTPORT:
sv = uint_to_SV(rec->dstport, 1);
break;
case NFL_I_TCP_FLAGS:
sv = uint_to_SV(rec->tcp_flags, 1);
break;
// Required extension 1 - IP addresses
// NOTE: srcaddr and dst addr do not uses ip_addr_t union/structure
// however the structures are compatible so we will pretend
// that v6.srcaddr and v6.dst addr points to same structure
case NFL_I_SRCADDR:
sv = ip_addr_to_SV((ip_addr_t *)&rec->v6.srcaddr,
rec->flags & FLAG_IPV6_ADDR, 1);
break;
case NFL_I_DSTADDR:
sv = ip_addr_to_SV((ip_addr_t *)&rec->v6.dstaddr,
rec->flags & FLAG_IPV6_ADDR, 1);
break;
case NFL_I_IP_NEXTHOP:
sv = ip_addr_to_SV(&rec->ip_nexthop, rec->flags & FLAG_IPV6_NH,
bit_array_get(&instance->ext_r, EX_NEXT_HOP_v4) ||
bit_array_get(&instance->ext_r, EX_NEXT_HOP_v6) );
break;
case NFL_I_SRC_MASK:
sv = uint_to_SV(rec->src_mask,
bit_array_get(&instance->ext_r, EX_MULIPLE) );
break;
case NFL_I_DST_MASK:
sv = uint_to_SV(rec->dst_mask,
bit_array_get(&instance->ext_r, EX_MULIPLE) );
break;
case NFL_I_TOS:
sv = uint_to_SV(rec->tos, 1);
break;
case NFL_I_DST_TOS:
sv = uint_to_SV(rec->dst_tos,
bit_array_get(&instance->ext_r, EX_MULIPLE) );
break;
case NFL_I_SRCAS:
sv = uint_to_SV(rec->srcas,
bit_array_get(&instance->ext_r, EX_AS_2) ||
bit_array_get(&instance->ext_r, EX_AS_4) );
break;
case NFL_I_DSTAS:
sv = uint_to_SV(rec->dstas,
bit_array_get(&instance->ext_r, EX_AS_2) ||
bit_array_get(&instance->ext_r, EX_AS_4) );
break;
case NFL_I_BGPNEXTADJACENTAS:
sv = uint_to_SV(rec->bgpNextAdjacentAS,
bit_array_get(&instance->ext_r, EX_BGPADJ) );
break;
case NFL_I_BGPPREVADJACENTAS:
sv = uint_to_SV(rec->bgpPrevAdjacentAS,
bit_array_get(&instance->ext_r, EX_BGPADJ) );
break;
case NFL_I_BGP_NEXTHOP:
sv = ip_addr_to_SV(&rec->bgp_nexthop, rec->flags & FLAG_IPV6_NHB,
bit_array_get(&instance->ext_r, EX_NEXT_HOP_BGP_v4) ||
bit_array_get(&instance->ext_r, EX_NEXT_HOP_BGP_v6) );
break;
case NFL_I_PROT:
sv = uint_to_SV(rec->prot, 1);
break;
case NFL_I_SRC_VLAN:
sv = uint_to_SV(rec->src_vlan,
bit_array_get(&instance->ext_r, EX_VLAN) );
break;
case NFL_I_DST_VLAN:
sv = uint_to_SV(rec->dst_vlan,
bit_array_get(&instance->ext_r, EX_VLAN) );
break;
case NFL_I_IN_SRC_MAC:
sv = mac_to_SV((u_int8_t *)&rec->in_src_mac,
bit_array_get(&instance->ext_r, EX_MAC_1) );
break;
case NFL_I_OUT_DST_MAC:
sv = mac_to_SV((u_int8_t *)&rec->out_dst_mac,
bit_array_get(&instance->ext_r, EX_MAC_1) );
break;
case NFL_I_OUT_SRC_MAC:
sv = mac_to_SV((u_int8_t *)&rec->out_src_mac,
bit_array_get(&instance->ext_r, EX_MAC_2) );
break;
case NFL_I_IN_DST_MAC:
sv = mac_to_SV((u_int8_t *)&rec->in_dst_mac,
bit_array_get(&instance->ext_r, EX_MAC_2) );
break;
case NFL_I_MPLS_LABEL:
sv = mpls_to_SV((char *)&rec->mpls_label,
bit_array_get(&instance->ext_r, EX_MPLS) );
break;
case NFL_I_INPUT:
sv = uint_to_SV(rec->input,
bit_array_get(&instance->ext_r, EX_IO_SNMP_2) ||
bit_array_get(&instance->ext_r, EX_IO_SNMP_4) );
break;
case NFL_I_OUTPUT:
sv = uint_to_SV(rec->output,
bit_array_get(&instance->ext_r, EX_IO_SNMP_2) ||
bit_array_get(&instance->ext_r, EX_IO_SNMP_4) );
break;
case NFL_I_DIR:
sv = uint_to_SV(rec->dir,
bit_array_get(&instance->ext_r, EX_MULIPLE) );
break;
case NFL_I_FWD_STATUS:
sv = uint_to_SV(rec->fwd_status, 1);
break;
case NFL_I_IP_ROUTER:
sv = ip_addr_to_SV(&rec->ip_router, rec->flags & FLAG_IPV6_EXP,
bit_array_get(&instance->ext_r, EX_ROUTER_IP_v4) ||
bit_array_get(&instance->ext_r, EX_ROUTER_IP_v6) );
break;
case NFL_I_ENGINE_TYPE:
sv = uint_to_SV(rec->engine_type,
bit_array_get(&instance->ext_r, EX_ROUTER_ID) );
break;
case NFL_I_ENGINE_ID:
sv = uint_to_SV(rec->engine_id,
bit_array_get(&instance->ext_r, EX_ROUTER_ID) );
break;
// NSEL
#ifdef NSEL
case NFL_I_FLOW_START:
sv = uint64_to_SV(rec->flow_start,
bit_array_get(&instance->ext_r, EX_NSEL_COMMON) );
break;
case NFL_I_CONN_ID:
sv = uint_to_SV(rec->conn_id,
bit_array_get(&instance->ext_r, EX_NSEL_COMMON) );
break;
case NFL_I_ICMP_CODE:
sv = uint_to_SV(rec->icmp_code,
bit_array_get(&instance->ext_r, EX_NSEL_COMMON) );
break;
case NFL_I_ICMP_TYPE:
sv = uint_to_SV(rec->icmp_type,
bit_array_get(&instance->ext_r, EX_NSEL_COMMON) );
break;
case NFL_I_FW_EVENT:
sv = uint_to_SV(rec->fw_event,
bit_array_get(&instance->ext_r, EX_NSEL_COMMON) );
break;
case NFL_I_FW_XEVENT:
sv = uint_to_SV(rec->fw_xevent,
bit_array_get(&instance->ext_r, EX_NSEL_COMMON) );
break;
case NFL_I_XLATE_SRC_IP:
sv = ip_addr_to_SV(&rec->xlate_src_ip, rec->xlate_flags,
bit_array_get(&instance->ext_r, EX_NSEL_XLATE_IP_v4) ||
bit_array_get(&instance->ext_r, EX_NSEL_XLATE_IP_v6) );
break;
case NFL_I_XLATE_DST_IP:
sv = ip_addr_to_SV(&rec->xlate_dst_ip, rec->xlate_flags,
bit_array_get(&instance->ext_r, EX_NSEL_XLATE_IP_v4) ||
bit_array_get(&instance->ext_r, EX_NSEL_XLATE_IP_v6) );
break;
case NFL_I_XLATE_SRC_PORT:
sv = uint_to_SV(rec->xlate_src_port,
bit_array_get(&instance->ext_r, EX_NSEL_XLATE_PORTS) );
break;
case NFL_I_XLATE_DST_PORT:
sv = uint_to_SV(rec->xlate_dst_port,
bit_array_get(&instance->ext_r, EX_NSEL_XLATE_PORTS) );
break;
case NFL_I_INGRESS_ACL_ID:
sv = uint_to_SV(rec->ingress_acl_id[0],
bit_array_get(&instance->ext_r, EX_NSEL_ACL) );
break;
case NFL_I_INGRESS_ACE_ID:
sv = uint_to_SV(rec->ingress_acl_id[1],
bit_array_get(&instance->ext_r, EX_NSEL_ACL) );
break;
case NFL_I_INGRESS_XACE_ID:
sv = uint_to_SV(rec->ingress_acl_id[2],
bit_array_get(&instance->ext_r, EX_NSEL_ACL) );
break;
case NFL_I_EGRESS_ACL_ID:
sv = uint_to_SV(rec->egress_acl_id[0],
bit_array_get(&instance->ext_r, EX_NSEL_ACL) );
break;
case NFL_I_EGRESS_ACE_ID:
sv = uint_to_SV(rec->egress_acl_id[1],
bit_array_get(&instance->ext_r, EX_NSEL_ACL) );
break;
case NFL_I_EGRESS_XACE_ID:
sv = uint_to_SV(rec->egress_acl_id[2],
bit_array_get(&instance->ext_r, EX_NSEL_ACL) );
break;
case NFL_I_USERNAME:
if ( bit_array_get(&instance->ext_r, EX_NSEL_USER) ||
bit_array_get(&instance->ext_r, EX_NSEL_USER_MAX ) ) {
sv = newSVpvn(rec->username, strlen(rec->username));
} else {
sv = newSV(0);
}
break;
#endif //
// END OF NSEL
#ifdef NEL
// NEL support
case NFL_I_NAT_EVENT:
sv = uint_to_SV(rec->nat_event,
bit_array_get(&instance->ext_r, EX_NEL_COMMON) );
break;
case NFL_I_POST_SRC_PORT:
sv = uint_to_SV(rec->post_src_port,
bit_array_get(&instance->ext_r, EX_NEL_COMMON) );
break;
case NFL_I_POST_DST_PORT:
sv = uint_to_SV(rec->post_dst_port,
bit_array_get(&instance->ext_r, EX_NEL_COMMON) );
break;
case NFL_I_INGRESS_VRFID:
sv = uint_to_SV(rec->ingress_vrfid,
bit_array_get(&instance->ext_r, EX_NEL_COMMON) );
break;
case NFL_I_NAT_INSIDE:
sv = ip_addr_to_SV(&rec->nat_inside, rec->nat_flags,
bit_array_get(&instance->ext_r, EX_NEL_GLOBAL_IP_v4) ||
bit_array_get(&instance->ext_r, EX_NEL_GLOBAL_IP_v6) );
break;
case NFL_I_NAT_OUTSIDE:
sv = ip_addr_to_SV(&rec->nat_outside, rec->nat_flags,
bit_array_get(&instance->ext_r, EX_NEL_GLOBAL_IP_v4) ||
bit_array_get(&instance->ext_r, EX_NEL_GLOBAL_IP_v6) );
break;
// END OF NEL
#endif // NEL
case NFL_I_CLIENT_NW_DELAY_USEC:
sv = uint64_to_SV(rec->client_nw_delay_usec,
bit_array_get(&instance->ext_r, EX_LATENCY) );
break;
case NFL_I_SERVER_NW_DELAY_USEC:
sv = uint64_to_SV(rec->server_nw_delay_usec,
bit_array_get(&instance->ext_r, EX_LATENCY) );
break;
case NFL_I_APPL_LATENCY_USEC:
sv = uint64_to_SV(rec->appl_latency_usec,
bit_array_get(&instance->ext_r, EX_LATENCY) );
break;
default:
croak("%s Unknown ID in %s !!", NFL_LOG, __FUNCTION__);
break;
}
i++;
av_push(res_array, sv);
}
return newRV((SV *)res_array);
}
extension_map_t * libnf_lookup_map( libnf_instance_t *instance, bit_array_t *ext ) {
extension_map_t *map;
libnf_map_list_t *map_list;
int i = 0;
int is_set = 0;
int id = 0;
int map_id = 0;
// find whether the template already exist
map_id = 0;
map_list = instance->map_list;
if (map_list == NULL) {
// first map
map_list = malloc(sizeof(libnf_map_list_t));
instance->map_list = map_list;
} else {
if (bit_array_cmp(&(map_list->bit_array), ext) == 0) {
return map_list->map;
}
map_id++;
while (map_list->next != NULL ) {
if (bit_array_cmp(&(map_list->bit_array), ext) == 0) {
return map_list->map;
} else {
map_id++;
map_list = map_list->next;
}
}
map_list->next = malloc(sizeof(libnf_map_list_t));
map_list = map_list->next;
}
// allocate memory potentially for all extensions
map = malloc(sizeof(extension_map_t) + (instance->max_num_extensions + 1) * sizeof(uint16_t));
map_list->map = map;
map_list->next = NULL;
bit_array_init(&map_list->bit_array, instance->max_num_extensions + 1);
bit_array_copy(&map_list->bit_array, ext);
map->type = ExtensionMapType;
map->map_id = map_id;
// set extension map according the bits set in ext structure
id = 0;
i = 0;
while ( (is_set = bit_array_get(ext, id)) != -1 ) {
// fprintf(stderr, "i: %d, bit %d, val: %d\n", i, id, is_set);
if (is_set)
map->ex_id[i++] = id;
id++;
}
map->ex_id[i++] = 0;
// determine size and align 32bits
map->size = sizeof(extension_map_t) + ( i - 1 ) * sizeof(uint16_t);
if (( map->size & 0x3 ) != 0 ) {
map->size += (4 - ( map->size & 0x3 ));
}
map->extension_size = 0;
i=0;
while (map->ex_id[i]) {
int id = map->ex_id[i];
map->extension_size += extension_descriptor[id].size;
i++;
}
Insert_Extension_Map(&instance->extension_map_list, map);
AppendToBuffer(instance->nffile_w, (void *)map, map->size);
return map;
}
int libnf_init(void) {
int handle = 1;
libnf_instance_t *instance;
//char *filter = NULL;
int i;
/* find the first free handler and assign to array of open handlers/instances */
while (libnf_instances[handle] != NULL) {
handle++;
if (handle >= NFL_MAX_INSTANCES - 1) {
croak("% no free handles available, max instances %d reached", NFL_LOG, NFL_MAX_INSTANCES);
return 0;
}
}
instance = malloc(sizeof(libnf_instance_t));
memset(instance, 0, sizeof(libnf_instance_t));
if (instance == NULL) {
croak("% can not allocate memory for instance:", NFL_LOG );
return 0;
}
instance->map_list = NULL;
libnf_instances[handle] = instance;
InitExtensionMaps(&(instance->extension_map_list));
i = 1;
instance->max_num_extensions = 0;
while ( extension_descriptor[i++].id )
instance->max_num_extensions++;
bit_array_init(&instance->ext_r, instance->max_num_extensions + 1);
bit_array_init(&instance->ext_w, instance->max_num_extensions + 1);
instance->nffile_w = NULL;
instance->master_record_r = NULL;
return handle;
}
int libnf_set_fields(int handle, SV *fields) {
libnf_instance_t *instance = libnf_instances[handle];
I32 last_field = 0;
int i;
if (instance == NULL ) {
croak("%s handler %d not initialized", NFL_LOG);
return 0;
}
if ((!SvROK(fields))
|| (SvTYPE(SvRV(fields)) != SVt_PVAV)
|| ((last_field = av_len((AV *)SvRV(fields))) < 0)) {
croak("%s can not determine the list of fields", NFL_LOG);
return 0;
}
// release memory allocated before
if (instance->field_list != NULL) {
free(instance->field_list);
}
// last_field contains the highet index of array ! - not number of items
instance->field_list = malloc(sizeof(int) * (last_field + 2));
if (instance->field_list == NULL) {
croak("%s can not allocate memory in %s", NFL_LOG, __FUNCTION__);
return 0;
}
for (i = 0; i <= last_field; i++) {
int field = SvIV(*av_fetch((AV *)SvRV(fields), i, 0));
if (field != 0 || field > NFL_MAX_FIELDS) {
instance->field_list[i] = field;
} else {
warn("%s ivalid itemd ID", NFL_LOG);
}
}
instance->field_list[i++] = NFL_ZERO_FIELD;
instance->field_last = last_field;
return 1;
}
int libnf_read_files(int handle, char *filter, int window_start, int window_end, SV *files) {
libnf_instance_t *instance = libnf_instances[handle];
libnf_file_list_t *pfile;
I32 numfiles = 0;
int i;
if (instance == NULL ) {
croak("%s handler %d not initialized", NFL_LOG);
return 0;
}
/* copy files to the instance structure */
if ((!SvROK(files))
|| (SvTYPE(SvRV(files)) != SVt_PVAV)
|| ((numfiles = av_len((AV *)SvRV(files))) < 0)) {
croak("%s can not determine the list of files", NFL_LOG);
return 0;
}
pfile = malloc(sizeof(libnf_file_list_t));
pfile->next = NULL;
pfile->filename = NULL;
instance->files = pfile;
instance->total_files = numfiles + 1;
for (i = 0; i <= numfiles; i++) {
STRLEN l;
char * file = SvPV(*av_fetch((AV *)SvRV(files), i, 0), l);
pfile->filename = malloc(l + 1);
strcpy((char *)(pfile->filename), file);
pfile->next = malloc(sizeof(libnf_file_list_t));
pfile = pfile->next;
pfile->filename = NULL;
}
instance->nffile_r = NULL;
/* set filter */
if (filter == NULL || strcmp(filter, "") == 0) {
filter = "any";
}
instance->engine = CompileFilter(filter);
if ( !instance->engine ) {
croak("%s can not setup filter (%s)", NFL_LOG, filter);
return 0;
}
return 1;
}
int libnf_create_file(int handle, char *filename, int compressed, int anonymized, char *ident) {
libnf_instance_t *instance = libnf_instances[handle];
if (instance == NULL ) {
croak("%s handler %d not initialized", NFL_LOG);
return 0;
}
/* the file was already opened */
if (instance->nffile_w != NULL) {
croak("%s file handler was opened before", NFL_LOG);
return 0;
}
/* writing file */
instance->nffile_w = OpenNewFile(filename, NULL, compressed, anonymized, ident);
if ( !instance->nffile_w ) {
warn("%s cannot open file %s", NFL_LOG, filename);
return 0;
}
memzero(&instance->master_record_w, sizeof(master_record_t)); // clean rec for write row
return 1;
}
/* returns hashref or NULL if we are et the end of the file */
SV * libnf_read_row(int handle) {
//master_record_t *master_record;
libnf_instance_t *instance = libnf_instances[handle];
int ret;
int match;
uint32_t map_id;
if (instance == NULL ) {
croak("%s handler %d not initialized", NFL_LOG);
return 0;
}
#ifdef COMPAT15
int v1_map_done = 0;
#endif
begin:
if (instance->blk_record_remains == 0) {
/* all records in block have been processed, we are going to load nex block */
// get next data block from file
if (instance->nffile_r) {
ret = ReadBlock(instance->nffile_r);
instance->processed_blocks++;
instance->current_processed_blocks++;
} else {
ret = NF_EOF; /* the firt file in the list */
}
switch (ret) {
case NF_CORRUPT:
LogError("Skip corrupt data file '%s'\n",GetCurrentFilename());
exit(1);
case NF_ERROR:
LogError("Read error in file '%s': %s\n",GetCurrentFilename(), strerror(errno) );
exit(1);
// fall through - get next file in chain
case NF_EOF: {
libnf_file_list_t *next;
//nffile_t *next = GetNextFile(nffile_r, twin_start, twin_end);
CloseFile(instance->nffile_r);
if (instance->files->filename == NULL) { // the end of the list
free(instance->files);
instance->files = NULL;
return NULL;
}
instance->nffile_r = OpenFile((char *)instance->files->filename, instance->nffile_r);
instance->processed_files++;
instance->current_processed_blocks = 0;
next = instance->files->next;
/* prepare instance->files to nex unread file */
if (instance->current_filename != NULL) {
free(instance->current_filename);
}
instance->current_filename = instance->files->filename;
free(instance->files);
instance->files = next;
if ( instance->nffile_r == NULL ) {
croak("%s can not read file %s", NFL_LOG, instance->files->filename);
return NULL;
}
goto begin;
}
default:
// successfully read block
instance->processed_bytes += ret;
}
switch (instance->nffile_r->block_header->id) {
case Large_BLOCK_Type:
goto begin;
break;
case ExporterRecordType:
goto begin;
break;
case SamplerRecordype:
goto begin;
break;
case ExporterInfoRecordType:
goto begin;
break;
case ExporterStatRecordType:
goto begin;
break;
case SamplerInfoRecordype:
goto begin;
break;
}
if ( instance->nffile_r->block_header->id == Large_BLOCK_Type ) {
goto begin;
}
if ( instance->nffile_r->block_header->id != DATA_BLOCK_TYPE_2 ) {
if ( instance->nffile_r->block_header->id == DATA_BLOCK_TYPE_1 ) {
croak("%s Can't process nfdump 1.5.x block type 1. Block skipped.", NFL_LOG);
return NULL;
} else {
croak("%s Can't process block type %u. Block skipped.", NFL_LOG, instance->nffile_r->block_header->id);
return NULL;
}
instance->skipped_blocks++;
goto begin;
}
instance->flow_record = instance->nffile_r->buff_ptr;
instance->blk_record_remains = instance->nffile_r->block_header->NumRecords;
}
/* there are some records to process - we are going continue reading next record */
instance->blk_record_remains--;
if ( instance->flow_record->type == ExtensionMapType ) {
extension_map_t *map = (extension_map_t *)instance->flow_record;
Insert_Extension_Map(&instance->extension_map_list, map);
instance->flow_record = (common_record_t *)((pointer_addr_t)instance->flow_record + instance->flow_record->size);
goto begin;
} else if ( instance->flow_record->type != CommonRecordType ) {
warn("%s Skip unknown record type %i\n", NFL_LOG, instance->flow_record->type);
instance->flow_record = (common_record_t *)((pointer_addr_t)instance->flow_record + instance->flow_record->size);
goto begin;
}
/* we are sure that record is CommonRecordType */
map_id = instance->flow_record->ext_map;
if ( map_id >= MAX_EXTENSION_MAPS ) {
croak("%s Corrupt data file. Extension map id %u too big.\n", NFL_LOG, instance->flow_record->ext_map);
return 0;
}
if ( instance->extension_map_list.slot[map_id] == NULL ) {
warn("%s Corrupt data file. Missing extension map %u. Skip record.\n", NFL_LOG, instance->flow_record->ext_map);
instance->flow_record = (common_record_t *)((pointer_addr_t)instance->flow_record + instance->flow_record->size);
goto begin;
}
instance->processed_records++;
instance->master_record_r = &(instance->extension_map_list.slot[map_id]->master_record);
instance->engine->nfrecord = (uint64_t *)instance->master_record_r;
// changed in 1.6.8 - added exporter info
// ExpandRecord_v2( flow_record, extension_map_list.slot[map_id], master_record);
ExpandRecord_v2( instance->flow_record, instance->extension_map_list.slot[map_id], NULL, instance->master_record_r);
// Time based filter
// if no time filter is given, the result is always true
match = instance->twin_start && (instance->master_record_r->first < instance->twin_start ||
instance->master_record_r->last > instance->twin_end) ? 0 : 1;
// filter netflow record with user supplied filter
if ( match )
match = (*instance->engine->FilterEngine)(instance->engine);
if ( match == 0 ) { // record failed to pass all filters
// increment pointer by number of bytes for netflow record
instance->flow_record = (common_record_t *)((pointer_addr_t)instance->flow_record + instance->flow_record->size);
goto begin;
}
// update number of flows matching a given map
instance->extension_map_list.slot[map_id]->ref_count++;
// Advance pointer by number of bytes for netflow record
instance->flow_record = (common_record_t *)((pointer_addr_t)instance->flow_record + instance->flow_record->size);
/*
{
char *s;
PrintExtensionMap(instance->extension_map_list.slot[map_id]->map);
format_file_block_record(master_record, &s, 0);
printf("READ: %s\n", s);
}
*/
/* the record seems OK. We prepare hash reference with items */
return libnf_master_record_to_AV(handle, instance->master_record_r, instance->extension_map_list.slot[map_id]->map);
} /* end of _next fnction */
/* copy row from the instance defined as the source handle to destination */
int libnf_copy_row(int handle, int src_handle) {
libnf_instance_t *instance = libnf_instances[handle];
libnf_instance_t *src_instance = libnf_instances[src_handle];
if (instance == NULL ) {
croak("%s handler %d not initialized", NFL_LOG);
return 0;
}
if (src_instance == NULL ) {
croak("%s seource handler %d not initialized", NFL_LOG);
return 0;
}
memcpy(&instance->master_record_w, src_instance->master_record_r, sizeof(master_record_t));
bit_array_copy(&instance->ext_w, &src_instance->ext_r);
return 1;
}
/* TAG for check_items_map.pl: libnf_write_row */
int libnf_write_row(int handle, SV * arrayref) {
master_record_t *rec;
libnf_instance_t *instance = libnf_instances[handle];
extension_map_t *map;
//bit_array_t ext;
int last_field;
int i, res;
uint64_t t;
if (instance == NULL ) {
croak("%s handler %d not initialized", NFL_LOG);
return 0;
}
if ((!SvROK(arrayref))
|| (SvTYPE(SvRV(arrayref)) != SVt_PVAV)
|| ((last_field = av_len((AV *)SvRV(arrayref))) < 0)) {
croak("%s can not determine fields to store", NFL_LOG);
return 0;
}
if (last_field != instance->field_last) {
croak("%s number of fields do not match", NFL_LOG);
return 0;
}
rec = &instance->master_record_w;
i = 0;
while ( instance->field_list[i] ) {
SV * sv = (SV *)(*av_fetch((AV *)SvRV(arrayref), i, 0));
if (!SvOK(sv)) { // undef value
i++;
continue;
}
switch ( instance->field_list[i] ) {
case NFL_I_FIRST:
t = SvU64(sv);
rec->first = t / 1000LL;
rec->msec_first = t - rec->first * 1000LL;
break;
case NFL_I_LAST:
t = SvU64(sv);
rec->last = t / 1000LL;
rec->msec_last = t - rec->last * 1000LL;
break;
case NFL_I_RECEIVED:
rec->received = SvU64(sv);
bit_array_set(&instance->ext_w, EX_RECEIVED, 1);
break;
case NFL_I_DPKTS:
rec->dPkts = SvU64(sv);
break;
case NFL_I_DOCTETS:
rec->dOctets = SvU64(sv);
break;
// EX_OUT_PKG_4 not used
case NFL_I_OUT_PKTS:
rec->out_pkts = SvU64(sv);
bit_array_set(&instance->ext_w, EX_OUT_PKG_8, 1);
break;
// EX_OUT_BYTES_4 not used
case NFL_I_OUT_BYTES:
rec->out_bytes = SvU64(sv);
bit_array_set(&instance->ext_w, EX_OUT_BYTES_8, 1);
break;
// EX_AGGR_FLOWS_4 not used
case NFL_I_AGGR_FLOWS:
rec->aggr_flows = SvU64(sv);
bit_array_set(&instance->ext_w, EX_AGGR_FLOWS_8, 1);
break;
case NFL_I_SRCPORT:
rec->srcport = SvUV(sv);
break;
case NFL_I_DSTPORT:
rec->dstport = SvUV(sv);
break;
case NFL_I_TCP_FLAGS:
rec->tcp_flags = SvUV(sv);
break;
// Required extension 1 - IP addresses
// NOTE: srcaddr and dst addr do not uses ip_addr_t union/structure
// however the structures are compatible so we will pretend
// that v6.srcaddr and v6.dst addr points to same structure
case NFL_I_SRCADDR:
res = SV_to_ip_addr((ip_addr_t *)&rec->v6.srcaddr, sv);
switch (res) {
case AF_INET:
ClearFlag(rec->flags, FLAG_IPV6_ADDR);
break;
case AF_INET6:
SetFlag(rec->flags, FLAG_IPV6_ADDR);
break;
default:
warn("%s invalid value for %s", NFL_LOG, NFL_T_SRCADDR);
bit_array_clear(&instance->ext_w);
return 0;
}
break;
case NFL_I_DSTADDR:
res = SV_to_ip_addr((ip_addr_t *)&rec->v6.dstaddr, sv);
switch (res) {
case AF_INET:
ClearFlag(rec->flags, FLAG_IPV6_ADDR);
break;
case AF_INET6:
SetFlag(rec->flags, FLAG_IPV6_ADDR);
break;
default:
warn("%s invalid value for %s", NFL_LOG, NFL_T_DSTADDR);
bit_array_clear(&instance->ext_w);
return 0;
}
break;
case NFL_I_IP_NEXTHOP:
res = SV_to_ip_addr((ip_addr_t *)&rec->ip_nexthop, sv);
switch (res) {
case AF_INET:
ClearFlag(rec->flags, FLAG_IPV6_NH);
bit_array_set(&instance->ext_w, EX_NEXT_HOP_v4, 1);
break;
case AF_INET6:
SetFlag(rec->flags, FLAG_IPV6_NH);
bit_array_set(&instance->ext_w, EX_NEXT_HOP_v6, 1);
break;
default:
warn("%s invalid value for %s", NFL_LOG, NFL_T_IP_NEXTHOP);
bit_array_clear(&instance->ext_w);
return 0;
}
break;
case NFL_I_SRC_MASK:
rec->src_mask = SvUV(sv);
bit_array_set(&instance->ext_w, EX_MULIPLE, 1);
break;
case NFL_I_DST_MASK:
rec->dst_mask = SvUV(sv);
bit_array_set(&instance->ext_w, EX_MULIPLE, 1);
break;
case NFL_I_TOS:
rec->tos = SvUV(sv);
break;
case NFL_I_DST_TOS:
rec->dst_tos = SvUV(sv);
bit_array_set(&instance->ext_w, EX_MULIPLE, 1);
break;
// EX_AS_2 not used
case NFL_I_SRCAS:
rec->srcas = SvUV(sv);
bit_array_set(&instance->ext_w, EX_AS_4, 1);
break;
case NFL_I_DSTAS:
rec->dstas = SvUV(sv);
bit_array_set(&instance->ext_w, EX_AS_4, 1);
break;
case NFL_I_BGPNEXTADJACENTAS:
rec->bgpNextAdjacentAS = SvUV(sv);
bit_array_set(&instance->ext_w, EX_BGPADJ, 1);
break;
case NFL_I_BGPPREVADJACENTAS:
rec->bgpPrevAdjacentAS = SvUV(sv);
bit_array_set(&instance->ext_w, EX_BGPADJ, 1);
break;
case NFL_I_BGP_NEXTHOP:
res = SV_to_ip_addr((ip_addr_t *)&rec->bgp_nexthop, sv);
switch (res) {
case AF_INET:
ClearFlag(rec->flags, FLAG_IPV6_NHB);
bit_array_set(&instance->ext_w, EX_NEXT_HOP_BGP_v4, 1);
break;
case AF_INET6:
SetFlag(rec->flags, FLAG_IPV6_NHB);
bit_array_set(&instance->ext_w, EX_NEXT_HOP_BGP_v6, 1);
break;
default:
warn("%s invalid value for %s", NFL_LOG, NFL_T_BGP_NEXTHOP);
bit_array_clear(&instance->ext_w);
return 0;
}
break;
case NFL_I_PROT:
rec->prot = SvUV(sv);
break;
case NFL_I_SRC_VLAN:
rec->src_vlan = SvUV(sv);
bit_array_set(&instance->ext_w, EX_VLAN, 1);
break;
case NFL_I_DST_VLAN:
rec->dst_vlan = SvUV(sv);
bit_array_set(&instance->ext_w, EX_VLAN, 1);
break;
case NFL_I_IN_SRC_MAC:
if (SV_to_mac(&rec->in_src_mac, sv) != 0) {
warn("%s invalid MAC address %s", NFL_LOG, NFL_T_IN_SRC_MAC);
bit_array_clear(&instance->ext_w);
return 0;
}
bit_array_set(&instance->ext_w, EX_MAC_1, 1);
break;
case NFL_I_OUT_DST_MAC:
if (SV_to_mac(&rec->out_dst_mac, sv) != 0) {
warn("%s invalid MAC address %s", NFL_LOG, NFL_T_OUT_DST_MAC);
bit_array_release(&instance->ext_w);
return 0;
}
bit_array_set(&instance->ext_w, EX_MAC_1, 1);
break;
case NFL_I_OUT_SRC_MAC:
if (SV_to_mac(&rec->out_src_mac, sv) != 0) {
warn("%s invalid MAC address %s", NFL_LOG, NFL_T_OUT_SRC_MAC);
bit_array_clear(&instance->ext_w);
return 0;
}
bit_array_set(&instance->ext_w, EX_MAC_2, 1);
break;
case NFL_I_IN_DST_MAC:
if (SV_to_mac(&rec->in_dst_mac, sv) != 0) {
warn("%s invalid MAC address %s", NFL_LOG, NFL_T_IN_DST_MAC);
bit_array_clear(&instance->ext_w);
return 0;
}
bit_array_set(&instance->ext_w, EX_MAC_2, 1);
break;
case NFL_I_MPLS_LABEL:
if (SV_to_mpls((char *)&rec->mpls_label, sv) != 0) {
warn("%s invalid item %s", NFL_LOG, NFL_T_MPLS_LABEL);
bit_array_clear(&instance->ext_w);
return 0;
}
bit_array_set(&instance->ext_w, EX_MPLS, 1);
break;
// EX_IO_SNMP_2 not used
case NFL_I_INPUT:
rec->input = SvUV(sv);
bit_array_set(&instance->ext_w, EX_IO_SNMP_4, 1);
break;
case NFL_I_OUTPUT:
rec->output = SvUV(sv);
bit_array_set(&instance->ext_w, EX_IO_SNMP_4, 1);
break;
case NFL_I_DIR:
rec->dir = SvUV(sv);
bit_array_set(&instance->ext_w, EX_MULIPLE, 1);
break;
case NFL_I_FWD_STATUS:
rec->fwd_status = SvUV(sv);
break;
case NFL_I_IP_ROUTER:
res = SV_to_ip_addr((ip_addr_t *)&rec->ip_router, sv);
switch (res) {
case AF_INET:
ClearFlag(rec->flags, FLAG_IPV6_EXP);
bit_array_set(&instance->ext_w, EX_ROUTER_IP_v4, 1);
break;
case AF_INET6:
SetFlag(rec->flags, FLAG_IPV6_EXP);
bit_array_set(&instance->ext_w, EX_ROUTER_IP_v6, 1);
break;
default:
warn("%s invalid value for %s", NFL_LOG, NFL_T_IP_ROUTER);
bit_array_clear(&instance->ext_w);
return 0;
}
break;
case NFL_I_ENGINE_TYPE:
rec->engine_type = SvUV(sv);
bit_array_set(&instance->ext_w, EX_ROUTER_ID, 1);
break;
case NFL_I_ENGINE_ID:
rec->engine_id = SvUV(sv);
bit_array_set(&instance->ext_w, EX_ROUTER_ID, 1);
break;
// NSEL
#ifdef NSEL
case NFL_I_FLOW_START:
rec->flow_start = SvU64(sv);
bit_array_set(&instance->ext_w, EX_NSEL_COMMON, 1);
break;
case NFL_I_CONN_ID:
rec->conn_id = SvUV(sv);
bit_array_set(&instance->ext_w, EX_NSEL_COMMON, 1);
break;
case NFL_I_ICMP_CODE:
rec->icmp_code = SvUV(sv);
bit_array_set(&instance->ext_w, EX_NSEL_COMMON, 1);
break;
case NFL_I_ICMP_TYPE:
rec->icmp_type = SvUV(sv);
bit_array_set(&instance->ext_w, EX_NSEL_COMMON, 1);
break;
case NFL_I_FW_EVENT:
rec->fw_event = SvUV(sv);
bit_array_set(&instance->ext_w, EX_NSEL_COMMON, 1);
break;
case NFL_I_FW_XEVENT:
rec->fw_xevent = SvUV(sv);
bit_array_set(&instance->ext_w, EX_NSEL_COMMON, 1);
break;
case NFL_I_XLATE_SRC_IP:
res = SV_to_ip_addr((ip_addr_t *)&rec->xlate_src_ip, sv);
switch (res) {
case AF_INET:
rec->xlate_flags = 0;
bit_array_set(&instance->ext_w, EX_NSEL_XLATE_IP_v4, 1);
break;
case AF_INET6:
rec->xlate_flags = 1;
bit_array_set(&instance->ext_w, EX_NSEL_XLATE_IP_v6, 1);
break;
default:
warn("%s invalid value for %s", NFL_LOG, NFL_T_XLATE_SRC_IP);
bit_array_clear(&instance->ext_w);
return 0;
}
break;
case NFL_I_XLATE_DST_IP:
res = SV_to_ip_addr((ip_addr_t *)&rec->xlate_dst_ip, sv);
switch (res) {
case AF_INET:
rec->xlate_flags = 0;
bit_array_set(&instance->ext_w, EX_NSEL_XLATE_IP_v4, 1);
break;
case AF_INET6:
rec->xlate_flags = 1;
bit_array_set(&instance->ext_w, EX_NSEL_XLATE_IP_v6, 1);
break;
default:
warn("%s invalid value for %s", NFL_LOG, NFL_T_XLATE_DST_IP);
bit_array_clear(&instance->ext_w);
return 0;
}
break;
case NFL_I_XLATE_SRC_PORT:
rec->xlate_src_port = SvUV(sv);
bit_array_set(&instance->ext_w, EX_NSEL_XLATE_PORTS, 1);
break;
case NFL_I_XLATE_DST_PORT:
rec->xlate_dst_port = SvUV(sv);
bit_array_set(&instance->ext_w, EX_NSEL_XLATE_PORTS, 1);
break;
case NFL_I_INGRESS_ACL_ID:
rec->ingress_acl_id[0] = SvUV(sv);
bit_array_set(&instance->ext_w, EX_NSEL_ACL, 1);
break;
case NFL_I_INGRESS_ACE_ID:
rec->ingress_acl_id[1] = SvUV(sv);
bit_array_set(&instance->ext_w, EX_NSEL_ACL, 1);
break;
case NFL_I_INGRESS_XACE_ID:
rec->ingress_acl_id[2] = SvUV(sv);
bit_array_set(&instance->ext_w, EX_NSEL_ACL, 1);
break;
case NFL_I_EGRESS_ACL_ID:
rec->egress_acl_id[0] = SvUV(sv);
bit_array_set(&instance->ext_w, EX_NSEL_ACL, 1);
break;
case NFL_I_EGRESS_ACE_ID:
rec->egress_acl_id[1] = SvUV(sv);
bit_array_set(&instance->ext_w, EX_NSEL_ACL, 1);
break;
case NFL_I_EGRESS_XACE_ID:
rec->egress_acl_id[2] = SvUV(sv);
bit_array_set(&instance->ext_w, EX_NSEL_ACL, 1);
break;
case NFL_I_USERNAME: {
STRLEN len;
char *s;
s = SvPV(sv, len);
if ( len > sizeof(rec->username) - 1 ) {
len = sizeof(rec->username) - 1;
}
memcpy(rec->username, s, len );
rec->username[len] = '\0'; // to be sure
if ( len < sizeof(((struct tpl_ext_42_s *)0)->username) - 1 ) {
bit_array_set(&instance->ext_w, EX_NSEL_USER, 1);
} else {
bit_array_set(&instance->ext_w, EX_NSEL_USER_MAX, 1);
}
}
break;
#endif
// END OF NSEL
// NEL support
#ifdef NEL
case NFL_I_NAT_EVENT:
rec->nat_event = SvUV(sv);
bit_array_set(&instance->ext_w, EX_NEL_COMMON, 1);
break;
case NFL_I_POST_SRC_PORT:
rec->post_src_port = SvUV(sv);
bit_array_set(&instance->ext_w, EX_NEL_COMMON, 1);
break;
case NFL_I_POST_DST_PORT:
rec->post_dst_port = SvUV(sv);
bit_array_set(&instance->ext_w, EX_NEL_COMMON, 1);
break;
case NFL_I_INGRESS_VRFID:
rec->ingress_vrfid = SvUV(sv);
bit_array_set(&instance->ext_w, EX_NEL_COMMON, 1);
break;
case NFL_I_NAT_INSIDE:
res = SV_to_ip_addr((ip_addr_t *)&rec->nat_inside, sv);
switch (res) {
case AF_INET:
rec->nat_flags = 0;
bit_array_set(&instance->ext_w, EX_NEL_GLOBAL_IP_v4, 1);
break;
case AF_INET6:
rec->nat_flags = 1;
bit_array_set(&instance->ext_w, EX_NEL_GLOBAL_IP_v6, 1);
break;
default:
warn("%s invalid value for %s", NFL_LOG, NFL_T_NAT_INSIDE);
bit_array_clear(&instance->ext_w);
return 0;
}
break;
case NFL_I_NAT_OUTSIDE:
res = SV_to_ip_addr((ip_addr_t *)&rec->nat_outside, sv);
switch (res) {
case AF_INET:
rec->nat_flags = 0;
bit_array_set(&instance->ext_w, EX_NEL_GLOBAL_IP_v4, 1);
break;
case AF_INET6:
rec->nat_flags = 1;
bit_array_set(&instance->ext_w, EX_NEL_GLOBAL_IP_v6, 1);
break;
default:
warn("%s invalid value for %s", NFL_LOG, NFL_T_NAT_OUTSIDE);
bit_array_clear(&instance->ext_w);
return 0;
}
break;
#endif
// END OF NEL
case NFL_I_CLIENT_NW_DELAY_USEC:
rec->client_nw_delay_usec = SvU64(sv);
bit_array_set(&instance->ext_w, EX_LATENCY, 1);
break;
case NFL_I_SERVER_NW_DELAY_USEC:
rec->server_nw_delay_usec = SvU64(sv);
bit_array_set(&instance->ext_w, EX_LATENCY, 1);
break;
case NFL_I_APPL_LATENCY_USEC:
rec->appl_latency_usec = SvU64(sv);
bit_array_set(&instance->ext_w, EX_LATENCY, 1);
break;
default:
croak("%s Unknown ID (%d) in %s !!", NFL_LOG, instance->field_list[i], __FUNCTION__);
break;
}
i++;
}
map = libnf_lookup_map(instance, &instance->ext_w);
rec->map_ref = map;
rec->ext_map = map->map_id;
rec->type = CommonRecordType;
bit_array_clear(&instance->ext_w);
/*
{
char *s;
PrintExtensionMap(map);
VerifyExtensionMap(map);
format_file_block_record(&rec, &s, 0);
printf("WRITE: (%p) \n%s\n", map, s);
}
*/
UpdateStat(instance->nffile_w->stat_record, rec);
PackRecord(rec, instance->nffile_w);
memzero(rec, sizeof(master_record_t)); // clean rec for next row
return 1;
}
void libnf_finish(int handle) {
libnf_instance_t *instance = libnf_instances[handle];
if (instance == NULL ) {
croak("%s handler %d not initialized", NFL_LOG);
return;
}
if (instance->nffile_w) {
// write the last records in buffer
if ( instance->nffile_w->block_header->NumRecords ) {
if ( WriteBlock(instance->nffile_w) <= 0 ) {
fprintf(stderr, "Failed to write output buffer: '%s'" , strerror(errno));
}
}
// CloseFile(instance->nffile_w);
CloseUpdateFile(instance->nffile_w, NULL );
DisposeFile(instance->nffile_w);
}
if (instance->nffile_r) {
CloseFile(instance->nffile_r);
DisposeFile(instance->nffile_r);
}
//release list of extensions map
// TODO
bit_array_release(&instance->ext_r);
bit_array_release(&instance->ext_w);
PackExtensionMapList(&instance->extension_map_list);
FreeExtensionMaps(&instance->extension_map_list);
free(instance);
libnf_instances[handle] = NULL;
//return stat_record;
return ;
} // End of process_data_finish