Commit 025c6746 authored by 's avatar

Added IPFIX/NetFlow capture & report function "IPFIXCAP". Usable for COMBO netflow design.

Captures flow reports from network or COMBO with netflow design (not via API) and reports
them via SHM to MAPI application. MAPI function is part of ipfixflib and is called "IPFIXCAP".



git-svn-id: file:///home/svn/mapi/trunk@1554 8d5bb341-7cf1-0310-8cf6-ba355fef3186
parent c3035d8d
......@@ -22,6 +22,7 @@ ipfixflib_la_SOURCES = \
engine.c engine.h\
ifp-priv.h \
ipfixlib.c \
ipfixcap.c \
ipfixprobe.c \
md5.c md5.h \
npctrl.c npctrl.h \
......@@ -34,6 +35,6 @@ services.c services.h \
util.c util.h
# these headers will be installd in $prefix/include/mapi
pkginclude_HEADERS = ipfixlib.h
pkginclude_HEADERS = ipfixlib.h ipfixcap.h
EXTRA_DIST = COPYING etter.passive.os.fp README-nprobe
This diff is collapsed.
This diff is collapsed.
......@@ -13,16 +13,21 @@
__attribute__ ((constructor)) void init ();
__attribute__ ((destructor)) void fini ();
mapidflib_functionlist_t functions[1];
mapidflib_functionlist_t functions[2];
extern mapidflib_function_def_t * ipfixp_get_funct_info();
extern mapidflib_function_def_t * ipfixcap_get_funct_info();
mapidflib_functionlist_t* mapidflib_get_function_list()
{
functions[0].def=ipfixp_get_funct_info();
functions[0].def->libname=libname;
functions[0].next=NULL;
functions[0].next=&functions[1];
functions[1].def=ipfixcap_get_funct_info();
functions[1].def->libname=libname;
functions[1].next=NULL;
return &functions[0];
}
......
......@@ -74,7 +74,7 @@
#define fragmentedPacketDst2Src(a) (NPROBE_FD_ISSET(FLAG_FRAGMENTED_PACKET_DST2SRC, &(a->flags)))
#ifdef linux
#define s6_addr32 in6_u.u6_addr32
#define s6_addr32 __in6_u.__u6_addr32
#else
#define s6_addr32 __u6_addr.__u6_addr32
#endif
......
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <signal.h>
#include <mapi.h>
#include "ipfixcap.h"
int fd = -1;
void terminate() {
int err_no = 0;
char error[512];
if(fd >= 0) {
if(mapi_close_flow(fd) < 0){
fprintf(stderr, "Close flow failed\n");
mapi_read_error(&err_no, error);
fprintf(stderr, "Errorcode :%d description: %s \n", err_no, error);
exit(-1);
}
}
exit(0);
}
void logts(FILE *fp, const time_t timestamp) {
char buffer[30];
//strftime(buffer, 30, "%Y/%m/%d %T %z", localtime(&timestamp));
//strftime(buffer, 30, "%Y/%m/%d %T %Z", localtime(&timestamp));
strftime(buffer, 30, "%Y/%m/%d %T", localtime(&timestamp));
fprintf(fp, "%s %lu", buffer, timestamp);
}
char *proto2name(u_short proto) {
static char proto_name[8];
switch(proto) {
case IPPROTO_TCP: return("TCP");
case IPPROTO_UDP: return("UDP");
case IPPROTO_ICMP: return("ICMP");
case IPPROTO_IGMP: return("IGMP");
default:
snprintf(proto_name, sizeof(proto_name), "%d", proto);
return(proto_name);
}
}
int main(int argc, char *argv[])
{
int fid;
mapi_results_t* res = NULL;
void* message = NULL;
ipfixcap_dgram_t* ipfixcap_dgram = NULL;
int err_no=0;
char error[512];
unsigned long long packets = 0;
unsigned long long bytes = 0;
if (argc != 3) {
fprintf(stderr, "\nWrong arguments\n");
return -1;
}
signal(SIGINT, terminate);
signal(SIGQUIT, terminate);
signal(SIGTERM, terminate);
if ((fd = mapi_create_flow(argv[1])) < 0) {
fprintf(stderr, "Could not create flow using '%s'\n", argv[1]);
mapi_read_error( &err_no, error);
fprintf(stderr,"Errorcode :%d description: %s \n" ,err_no, error);
return -1;
}
if ((fid = mapi_apply_function(fd, "IPFIXCAP", "IPFIX", argv[2])) == -1) {
fprintf(stderr, "Count not apply function IPFIXCAP to flow %d\n", fd);
mapi_read_error( &err_no, error);
fprintf(stderr,"Errorcode :%d description: %s \n" ,err_no, error);
return -1;
}
if (mapi_connect(fd) < 0) {
fprintf(stderr, "Could not connect to flow %d\n", fd);
mapi_read_error( &err_no, error);
fprintf(stderr,"Errorcode :%d description: %s \n" ,err_no, error);
return -1;
}
netflow_common_header_t *netflow_common_header;
ssize_t message_len = 0;
ssize_t message_todo;
int expected_flowset_size;
uint16_t version;
uint16_t count;
netflow_v5_header_t *netflow_v5_header;
netflow_v7_header_t *netflow_v7_header;
//netflow_v9_header_t *netflow_v9_header;
netflow_v5_record_t *netflow_v5_record;
netflow_v7_record_t *netflow_v7_record;
long long flow_sequence_num;
long long expected_sequence_num = -1;
long long lost_flows = 0;
while (1) {
sleep(1);
res = mapi_read_results(fd, fid);
if(res == NULL) {
logts(stdout, time(NULL));
printf("mapi_read_results returned NULL\n"); fflush(stdout);
fflush(stdout);
continue;
}
// paranoid check sizeof(res) < mapi_result_t)?
if (res->size < (ssize_t) sizeof(ipfixcap_dgram_t)) {
fprintf(stderr, "mapi result too short for ipfixcap_dgram_t. message_len: %zd\n", message_len);
continue; // XXX ignore bad results
}
ipfixcap_dgram = res->res;
message = ipfixcap_dgram->bytes;
message_len = ipfixcap_dgram->size;
// fprintf(stdout, "message_len: %d\n", message_len); fflush(stdout);
//if (message_len == -1 && errno != EINTR) {
// fprintf(stderr, "ERROR: recvfrom: %s\n", strerror(errno));
// continue;
//}
if (message_len < (ssize_t) sizeof(netflow_common_header_t)) {
fprintf(stderr, "message too short for common netflow header. message_len: %zd\n", message_len);
continue; // XXX ignore bad packets
}
netflow_common_header = (netflow_common_header_t *) message;
version = ntohs(netflow_common_header->version);
switch (version) {
case NETFLOW_V5_VERSION:
fprintf(stdout, "seems to be netflow_v5_message, message_len: %zd\n", message_len); fflush(stdout);
message_todo = message_len;
while(message_todo > 0) {
if(message_len < (int) sizeof(netflow_v5_header_t)) {
fprintf(stderr, "message too short for netflow_v5_message, message_len: %zd\n", message_len);
return -1;
}
netflow_v5_header = (netflow_v5_header_t *) message;
count = ntohs(netflow_v5_header->count);
if (count > NETFLOW_V5_RECORDS_IN_PACKET_MAX) {
fprintf(stderr, "too many records in netflow_v5 packet: %u, maximum is: %u\n", count, NETFLOW_V5_RECORDS_IN_PACKET_MAX);
return -1;
}
expected_flowset_size = sizeof(netflow_v5_header_t) + count * sizeof(netflow_v5_record_t);
if (message_todo < expected_flowset_size) {
fprintf(stderr, "rest of message too short for expected flowset size (netflow_v5_header + number of netflow_v5_records)\n");
return -1;
}
if (expected_sequence_num != -1) {
flow_sequence_num = ntohl(netflow_v5_header->flow_sequence_num);
if (flow_sequence_num != expected_sequence_num) { // FIXME overflow
lost_flows += flow_sequence_num - expected_sequence_num;
fprintf(stdout, "lost %lli flows, %lli total\n", flow_sequence_num - expected_sequence_num, lost_flows); fflush(stdout);
}
}
expected_sequence_num = ntohl(netflow_v5_header->flow_sequence_num) + count;
for (netflow_v5_record = (netflow_v5_record_t *) (netflow_v5_header + 1); netflow_v5_record < (netflow_v5_record_t *) (netflow_v5_header + 1) + count; netflow_v5_record++) {
packets += htonl((uint32_t) netflow_v5_record->packets);
bytes += htonl((uint32_t) netflow_v5_record->bytes);
//char buf[32]dd, buf1[32];
struct in_addr src;
struct in_addr dst;
src.s_addr = netflow_v5_record->src;
dst.s_addr = netflow_v5_record->dst;
fprintf(stdout, "[%s] %s:%d -> %s:%d [%d pkt][%d bytes]\n",
proto2name(netflow_v5_record->proto),
inet_ntoa(src),
htons(netflow_v5_record->sport),
inet_ntoa(dst),
htons(netflow_v5_record->dport),
htonl(netflow_v5_record->packets),
htonl(netflow_v5_record->bytes)
);
}
fprintf(stdout, "\n");
message_todo -= expected_flowset_size;
// next header
netflow_v5_header = (netflow_v5_header_t *) netflow_v5_record;
}
break;
case NETFLOW_V7_VERSION:
fprintf(stdout, "seems to be netflow_v7_message, message_len: %zd\n", message_len); fflush(stdout);
message_todo = message_len;
while(message_todo > 0) {
if(message_len < (int) sizeof(netflow_v7_header_t)) {
fprintf(stderr, "message too short for netflow_v7_message, message_len: %zd\n", message_len);
return -1;
}
netflow_v7_header = (netflow_v7_header_t *) message;
count = ntohs(netflow_v7_header->count);
if (count > NETFLOW_V7_RECORDS_IN_PACKET_MAX) {
fprintf(stderr, "too many records in netflow_v7 packet: %u, maximum is: %u\n", count, NETFLOW_V7_RECORDS_IN_PACKET_MAX);
return -1;
}
expected_flowset_size = sizeof(netflow_v7_header_t) + count * sizeof(netflow_v7_record_t);
if (message_todo < expected_flowset_size) {
fprintf(stderr, "rest of message too short for expected flowset size (netflow_v7_header + number of netflow_v7_records)\n");
return -1;
}
for (netflow_v7_record = (netflow_v7_record_t *) (netflow_v7_header + 1); netflow_v7_record < (netflow_v7_record_t *) (netflow_v7_header + 1) + count; netflow_v7_record++) {
packets += htonl((uint32_t) netflow_v7_record->packets);
bytes += htonl((uint32_t) netflow_v7_record->bytes);
//char buf[32]dd, buf1[32];
struct in_addr src;
struct in_addr dst;
src.s_addr = netflow_v7_record->src;
dst.s_addr = netflow_v7_record->dst;
fprintf(stdout, "[%s] %s:%d -> %s:%d [%d pkt][%d bytes]\n",
proto2name(netflow_v7_record->proto),
inet_ntoa(src),
htons(netflow_v7_record->sport),
inet_ntoa(dst),
htons(netflow_v7_record->dport),
htonl(netflow_v7_record->packets),
htonl(netflow_v7_record->bytes)
);
}
fprintf(stdout, "\n");
message_todo -= expected_flowset_size;
// next header
netflow_v7_header = (netflow_v7_header_t *) netflow_v7_record;
}
break;
case NETFLOW_V9_VERSION:
fprintf(stdout, "seems to be netflow_v9_message, message_len: %zd\n", message_len); fflush(stdout);
// TODO
break;
case IPFIX_VERSION:
fprintf(stdout, "seems to be ipfix_message, message_len: %zd\n", message_len); fflush(stdout);
// TODO
break;
default:
fprintf(stderr, "unexpected netflow version %i\n", netflow_common_header->version);
continue; // ignore unexpected packets
}
// each Process_xx function has to process the entire input buffer, therefore it's empty now.
//export_packets++;
logts(stdout, time(NULL));
printf(": %llu packets total, %lli bytes total, %lli lost flows total\n", packets, bytes, lost_flows);
printf("\n");
fflush(stdout);
}
terminate();
exit(0);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment