| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487 | /* * Copyright 2002 Damien Miller <djm@mindrot.org> All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. */#include "common.h"#include "log.h"#include "treetype.h"#include "softflowd.h"#include "netflow9.h"/* Netflow v.9 */struct NF9_FLOWSET_HEADER_COMMON {  u_int16_t flowset_id, length;} __packed;struct NF9_TEMPLATE_FLOWSET_HEADER {  struct NF9_FLOWSET_HEADER_COMMON c;  u_int16_t template_id, count;} __packed;struct NF9_OPTION_TEMPLATE_FLOWSET_HEADER {  struct NF9_FLOWSET_HEADER_COMMON c;  u_int16_t template_id, scope_length, option_length;} __packed;struct NF9_TEMPLATE_FLOWSET_RECORD {  u_int16_t type, length;} __packed;struct NF9_DATA_FLOWSET_HEADER {  struct NF9_FLOWSET_HEADER_COMMON c;} __packed;#define NF9_MIN_RECORD_FLOWSET_ID	256/* Flowset record types the we care about */#define NF9_IN_BYTES			1#define NF9_IN_PACKETS			2/* ... */#define NF9_PROTOCOL			4#define NF9_TOS				5/* ... */#define NF9_TCP_FLAGS			6#define NF9_L4_SRC_PORT			7#define NF9_IPV4_SRC_ADDR		8/* ... */#define NF9_IF_INDEX_IN			10#define NF9_L4_DST_PORT			11#define NF9_IPV4_DST_ADDR		12/* ... */#define NF9_IF_INDEX_OUT		14/* ... */#define NF9_LAST_SWITCHED		21#define NF9_FIRST_SWITCHED		22/* ... */#define NF9_IPV6_SRC_ADDR		27#define NF9_IPV6_DST_ADDR		28/* ... */#define NF9_ICMP_TYPE		        32/* ... */#define NF9_SRC_VLAN                    58/* ... */#define NF9_IP_PROTOCOL_VERSION		60/* Stuff pertaining to the templates that softflowd uses */#define NF9_SOFTFLOWD_TEMPLATE_NRECORDS	16struct NF9_SOFTFLOWD_TEMPLATE {  struct NF9_TEMPLATE_FLOWSET_HEADER h;  struct NF9_TEMPLATE_FLOWSET_RECORD r[NF9_SOFTFLOWD_TEMPLATE_NRECORDS];} __packed;#define NF9_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS	1#define NF9_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS	2struct NF9_SOFTFLOWD_OPTION_TEMPLATE {  struct NF9_OPTION_TEMPLATE_FLOWSET_HEADER h;  struct NF9_TEMPLATE_FLOWSET_RECORD    s[NF9_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS];  struct NF9_TEMPLATE_FLOWSET_RECORD    r[NF9_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS];} __packed;/* softflowd data flowset types */struct NF9_SOFTFLOWD_DATA_COMMON {  u_int32_t last_switched, first_switched;  u_int32_t bytes, packets;  u_int32_t if_index_in, if_index_out;  u_int16_t src_port, dst_port;  u_int8_t protocol, tcp_flags, ipproto, tos;  u_int16_t icmp_type, vlanid;} __packed;struct NF9_SOFTFLOWD_DATA_V4 {  u_int32_t src_addr, dst_addr;  struct NF9_SOFTFLOWD_DATA_COMMON c;} __packed;struct NF9_SOFTFLOWD_DATA_V6 {  u_int8_t src_addr[16], dst_addr[16];  struct NF9_SOFTFLOWD_DATA_COMMON c;} __packed;struct NF9_SOFTFLOWD_OPTION_DATA {  struct NF9_FLOWSET_HEADER_COMMON c;  u_int32_t scope_ifidx;  u_int32_t sampling_interval;  u_int8_t sampling_algorithm;  u_int8_t padding[3];} __packed;/* Local data: templates and counters */#define NF9_SOFTFLOWD_MAX_PACKET_SIZE	512#define NF9_SOFTFLOWD_V4_TEMPLATE_ID	1024#define NF9_SOFTFLOWD_V6_TEMPLATE_ID	2048#define NF9_SOFTFLOWD_OPTION_TEMPLATE_ID	256#define NF9_DEFAULT_TEMPLATE_INTERVAL	16/* ... */#define NF9_OPTION_SCOPE_SYSTEM    1#define NF9_OPTION_SCOPE_INTERFACE 2#define NF9_OPTION_SCOPE_LINECARD  3#define NF9_OPTION_SCOPE_CACHE     4#define NF9_OPTION_SCOPE_TEMPLATE  5static struct NF9_SOFTFLOWD_TEMPLATE v4_template;static struct NF9_SOFTFLOWD_TEMPLATE v6_template;static struct NF9_SOFTFLOWD_OPTION_TEMPLATE option_template;static struct NF9_SOFTFLOWD_OPTION_DATA option_data;static int nf9_pkts_until_template = -1;static voidnf9_init_template (void) {  memset (&v4_template, 0, sizeof (v4_template));  v4_template.h.c.flowset_id = htons (NFLOW9_TEMPLATE_SET_ID);  v4_template.h.c.length = htons (sizeof (v4_template));  v4_template.h.template_id = htons (NF9_SOFTFLOWD_V4_TEMPLATE_ID);  v4_template.h.count = htons (NF9_SOFTFLOWD_TEMPLATE_NRECORDS);  v4_template.r[0].type = htons (NF9_IPV4_SRC_ADDR);  v4_template.r[0].length = htons (4);  v4_template.r[1].type = htons (NF9_IPV4_DST_ADDR);  v4_template.r[1].length = htons (4);  v4_template.r[2].type = htons (NF9_LAST_SWITCHED);  v4_template.r[2].length = htons (4);  v4_template.r[3].type = htons (NF9_FIRST_SWITCHED);  v4_template.r[3].length = htons (4);  v4_template.r[4].type = htons (NF9_IN_BYTES);  v4_template.r[4].length = htons (4);  v4_template.r[5].type = htons (NF9_IN_PACKETS);  v4_template.r[5].length = htons (4);  v4_template.r[6].type = htons (NF9_IF_INDEX_IN);  v4_template.r[6].length = htons (4);  v4_template.r[7].type = htons (NF9_IF_INDEX_OUT);  v4_template.r[7].length = htons (4);  v4_template.r[8].type = htons (NF9_L4_SRC_PORT);  v4_template.r[8].length = htons (2);  v4_template.r[9].type = htons (NF9_L4_DST_PORT);  v4_template.r[9].length = htons (2);  v4_template.r[10].type = htons (NF9_PROTOCOL);  v4_template.r[10].length = htons (1);  v4_template.r[11].type = htons (NF9_TCP_FLAGS);  v4_template.r[11].length = htons (1);  v4_template.r[12].type = htons (NF9_IP_PROTOCOL_VERSION);  v4_template.r[12].length = htons (1);  v4_template.r[13].type = htons (NF9_TOS);  v4_template.r[13].length = htons (1);  v4_template.r[14].type = htons (NF9_ICMP_TYPE);  v4_template.r[14].length = htons (2);  v4_template.r[15].type = htons (NF9_SRC_VLAN);  v4_template.r[15].length = htons (2);  memset (&v6_template, 0, sizeof (v6_template));  v6_template.h.c.flowset_id = htons (NFLOW9_TEMPLATE_SET_ID);  v6_template.h.c.length = htons (sizeof (v6_template));  v6_template.h.template_id = htons (NF9_SOFTFLOWD_V6_TEMPLATE_ID);  v6_template.h.count = htons (NF9_SOFTFLOWD_TEMPLATE_NRECORDS);  v6_template.r[0].type = htons (NF9_IPV6_SRC_ADDR);  v6_template.r[0].length = htons (16);  v6_template.r[1].type = htons (NF9_IPV6_DST_ADDR);  v6_template.r[1].length = htons (16);  v6_template.r[2].type = htons (NF9_LAST_SWITCHED);  v6_template.r[2].length = htons (4);  v6_template.r[3].type = htons (NF9_FIRST_SWITCHED);  v6_template.r[3].length = htons (4);  v6_template.r[4].type = htons (NF9_IN_BYTES);  v6_template.r[4].length = htons (4);  v6_template.r[5].type = htons (NF9_IN_PACKETS);  v6_template.r[5].length = htons (4);  v6_template.r[6].type = htons (NF9_IF_INDEX_IN);  v6_template.r[6].length = htons (4);  v6_template.r[7].type = htons (NF9_IF_INDEX_OUT);  v6_template.r[7].length = htons (4);  v6_template.r[8].type = htons (NF9_L4_SRC_PORT);  v6_template.r[8].length = htons (2);  v6_template.r[9].type = htons (NF9_L4_DST_PORT);  v6_template.r[9].length = htons (2);  v6_template.r[10].type = htons (NF9_PROTOCOL);  v6_template.r[10].length = htons (1);  v6_template.r[11].type = htons (NF9_TCP_FLAGS);  v6_template.r[11].length = htons (1);  v6_template.r[12].type = htons (NF9_IP_PROTOCOL_VERSION);  v6_template.r[12].length = htons (1);  v6_template.r[13].type = htons (NF9_TOS);  v6_template.r[13].length = htons (1);  v6_template.r[14].type = htons (NF9_ICMP_TYPE);  v6_template.r[14].length = htons (2);  v6_template.r[15].type = htons (NF9_SRC_VLAN);  v6_template.r[15].length = htons (2);}static voidnf9_init_option (u_int16_t ifidx, struct OPTION *option) {  memset (&option_template, 0, sizeof (option_template));  option_template.h.c.flowset_id = htons (NFLOW9_OPTION_TEMPLATE_SET_ID);  option_template.h.c.length = htons (sizeof (option_template));  option_template.h.template_id = htons (NF9_SOFTFLOWD_OPTION_TEMPLATE_ID);  option_template.h.scope_length = htons (sizeof (option_template.s));  option_template.h.option_length = htons (sizeof (option_template.r));  option_template.s[0].type = htons (NF9_OPTION_SCOPE_INTERFACE);  option_template.s[0].length = htons (sizeof (option_data.scope_ifidx));  option_template.r[0].type = htons (NFLOW9_SAMPLING_INTERVAL);  option_template.r[0].length =    htons (sizeof (option_data.sampling_interval));  option_template.r[1].type = htons (NFLOW9_SAMPLING_ALGORITHM);  option_template.r[1].length =    htons (sizeof (option_data.sampling_algorithm));  memset (&option_data, 0, sizeof (option_data));  option_data.c.flowset_id = htons (NF9_SOFTFLOWD_OPTION_TEMPLATE_ID);  option_data.c.length = htons (sizeof (option_data));  option_data.scope_ifidx = htonl (ifidx);  option_data.sampling_interval = htonl (option->sample);  option_data.sampling_algorithm = NFLOW9_SAMPLING_ALGORITHM_DETERMINISTIC;}static intnf_flow_to_flowset (const struct FLOW *flow, u_char * packet, u_int len,                    u_int16_t ifidx, const struct timeval *system_boot_time,                    u_int * len_used) {  union {    struct NF9_SOFTFLOWD_DATA_V4 d4;    struct NF9_SOFTFLOWD_DATA_V6 d6;  } d[2];  struct NF9_SOFTFLOWD_DATA_COMMON *dc[2];  u_int freclen, ret_len, nflows;  memset (d, 0, sizeof (d));  *len_used = nflows = ret_len = 0;  switch (flow->af) {  case AF_INET:    freclen = sizeof (struct NF9_SOFTFLOWD_DATA_V4);    memcpy (&d[0].d4.src_addr, &flow->addr[0].v4, 4);    memcpy (&d[0].d4.dst_addr, &flow->addr[1].v4, 4);    memcpy (&d[1].d4.src_addr, &flow->addr[1].v4, 4);    memcpy (&d[1].d4.dst_addr, &flow->addr[0].v4, 4);    dc[0] = &d[0].d4.c;    dc[1] = &d[1].d4.c;    dc[0]->ipproto = dc[1]->ipproto = 4;    break;  case AF_INET6:    freclen = sizeof (struct NF9_SOFTFLOWD_DATA_V6);    memcpy (&d[0].d6.src_addr, &flow->addr[0].v6, 16);    memcpy (&d[0].d6.dst_addr, &flow->addr[1].v6, 16);    memcpy (&d[1].d6.src_addr, &flow->addr[1].v6, 16);    memcpy (&d[1].d6.dst_addr, &flow->addr[0].v6, 16);    dc[0] = &d[0].d6.c;    dc[1] = &d[1].d6.c;    dc[0]->ipproto = dc[1]->ipproto = 6;    break;  default:    return (-1);  }  dc[0]->first_switched = dc[1]->first_switched =    htonl (timeval_sub_ms (&flow->flow_start, system_boot_time));  dc[0]->last_switched = dc[1]->last_switched =    htonl (timeval_sub_ms (&flow->flow_last, system_boot_time));  dc[0]->bytes = htonl (flow->octets[0]);  dc[1]->bytes = htonl (flow->octets[1]);  dc[0]->packets = htonl (flow->packets[0]);  dc[1]->packets = htonl (flow->packets[1]);  dc[0]->if_index_in = dc[0]->if_index_out = htonl (ifidx);  dc[1]->if_index_in = dc[1]->if_index_out = htonl (ifidx);  dc[0]->src_port = dc[1]->dst_port = flow->port[0];  dc[1]->src_port = dc[0]->dst_port = flow->port[1];  dc[0]->protocol = dc[1]->protocol = flow->protocol;  dc[0]->tcp_flags = flow->tcp_flags[0];  dc[1]->tcp_flags = flow->tcp_flags[1];  dc[0]->tos = flow->tos[0];  dc[1]->tos = flow->tos[1];  if (flow->protocol == IPPROTO_ICMP || flow->protocol == IPPROTO_ICMPV6) {    dc[0]->icmp_type = dc[0]->dst_port;    dc[1]->icmp_type = dc[1]->dst_port;  }  dc[0]->vlanid = dc[1]->vlanid = htons (flow->vlanid[0]);  if (flow->octets[0] > 0) {    if (ret_len + freclen > len)      return (-1);    memcpy (packet + ret_len, &d[0], freclen);    ret_len += freclen;    nflows++;  }  if (flow->octets[1] > 0) {    if (ret_len + freclen > len)      return (-1);    memcpy (packet + ret_len, &d[1], freclen);    ret_len += freclen;    nflows++;  }  *len_used = ret_len;  return (nflows);}/* * Given an array of expired flows, send netflow v9 report packets * Returns number of packets sent or -1 on error */#ifdef ENABLE_LEGACYintsend_netflow_v9 (struct SENDPARAMETER sp) {  struct FLOW **flows = sp.flows;  int num_flows = sp.num_flows;  u_int16_t ifidx = sp.ifidx;  struct FLOWTRACKPARAMETERS *param = sp.param;  int verbose_flag = sp.verbose_flag;  struct NFLOW9_HEADER *nf9;  struct NF9_DATA_FLOWSET_HEADER *dh;  struct timeval now;  u_int offset, last_af, i, j, num_packets, inc, last_valid;  int r;  u_char packet[NF9_SOFTFLOWD_MAX_PACKET_SIZE];  struct timeval *system_boot_time = ¶m->system_boot_time;  u_int64_t *flows_exported = ¶m->flows_exported;  u_int64_t *packets_sent = ¶m->packets_sent;  struct OPTION *option = ¶m->option;  if (param->adjust_time)    now = param->last_packet_time;  else    gettimeofday (&now, NULL);  if (nf9_pkts_until_template == -1) {    nf9_init_template ();    nf9_pkts_until_template = 0;    if (option != NULL && option->sample > 1) {      nf9_init_option (ifidx, option);    }  }  last_valid = num_packets = 0;  for (j = 0; j < num_flows;) {    memset (packet, 0, sizeof (packet));    nf9 = (struct NFLOW9_HEADER *) packet;    nf9->version = htons (9);    nf9->flows = 0;             /* Filled as we go, htons at end */    nf9->uptime_ms = htonl (timeval_sub_ms (&now, system_boot_time));    nf9->export_time = htonl (time (NULL));    nf9->od_id = 0;    offset = sizeof (*nf9);    /* Refresh template headers if we need to */    if (nf9_pkts_until_template <= 0) {      memcpy (packet + offset, &v4_template, sizeof (v4_template));      offset += sizeof (v4_template);      nf9->flows++;      memcpy (packet + offset, &v6_template, sizeof (v6_template));      offset += sizeof (v6_template);      nf9->flows++;      if (option != NULL && option->sample > 1) {        memcpy (packet + offset, &option_template, sizeof (option_template));        offset += sizeof (option_template);        nf9->flows++;        memcpy (packet + offset, &option_data, sizeof (option_data));        offset += sizeof (option_data);        nf9->flows++;      }      nf9_pkts_until_template = NF9_DEFAULT_TEMPLATE_INTERVAL;    }    dh = NULL;    last_af = 0;    for (i = 0; i + j < num_flows; i++) {      if (dh == NULL || flows[i + j]->af != last_af) {        if (dh != NULL) {          if (offset % 4 != 0) {            /* Pad to multiple of 4 */            dh->c.length += 4 - (offset % 4);            offset += 4 - (offset % 4);          }          /* Finalise last header */          dh->c.length = htons (dh->c.length);        }        if (offset + sizeof (*dh) > sizeof (packet)) {          /* Mark header is finished */          dh = NULL;          break;        }        dh = (struct NF9_DATA_FLOWSET_HEADER *)          (packet + offset);        dh->c.flowset_id =          (flows[i + j]->af == AF_INET) ?          v4_template.h.template_id : v6_template.h.template_id;        last_af = flows[i + j]->af;        last_valid = offset;        dh->c.length = sizeof (*dh);    /* Filled as we go */        offset += sizeof (*dh);      }      r = nf_flow_to_flowset (flows[i + j], packet + offset,                              sizeof (packet) - offset, ifidx,                              system_boot_time, &inc);      if (r <= 0) {        /* yank off data header, if we had to go back */        if (last_valid)          offset = last_valid;        break;      }      offset += inc;      dh->c.length += inc;      nf9->flows += r;      last_valid = 0;           /* Don't clobber this header now */      if (verbose_flag) {        logit (LOG_DEBUG, "Flow %d/%d: "               "r %d offset %d type %04x len %d(0x%04x) "               "flows %d", r, i, j, offset,               dh->c.flowset_id, dh->c.length, dh->c.length, nf9->flows);      }    }    /* Don't finish header if it has already been done */    if (dh != NULL) {      if (offset % 4 != 0) {        /* Pad to multiple of 4 */        dh->c.length += 4 - (offset % 4);        offset += 4 - (offset % 4);      }      /* Finalise last header */      dh->c.length = htons (dh->c.length);    }    param->records_sent += nf9->flows;    nf9->flows = htons (nf9->flows);    nf9->sequence = htonl ((u_int32_t)                           ((*packets_sent + num_packets +                             1) & 0x00000000ffffffff));    if (verbose_flag)      logit (LOG_DEBUG, "Sending flow packet len = %d", offset);    if (send_multi_destinations        (sp.target->num_destinations, sp.target->destinations,         sp.target->is_loadbalance, packet, offset) < 0)      return (-1);    num_packets++;    nf9_pkts_until_template--;    j += i;  }  *flows_exported += j;  param->packets_sent += num_packets;#ifdef ENABLE_PTHREAD  if (use_thread)    free (sp.flows);#endif /* ENABLE_PTHREAD */  return (num_packets);}#endif /* ENABLE_LEGACY */voidnetflow9_resend_template (void) {  if (nf9_pkts_until_template > 0)    nf9_pkts_until_template = 0;}
 |