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 16
- struct 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 2
- struct 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 5
- static 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 void
- nf9_init_template (void) {
- bzero (&v4_template, 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);
- bzero (&v6_template, 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 void
- nf9_init_option (u_int16_t ifidx, struct OPTION *option) {
- bzero (&option_template, 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));
- bzero (&option_data, 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 int
- nf_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;
- bzero (d, 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_LEGACY
- int
- send_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;) {
- bzero (packet, 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 */
- void
- netflow9_resend_template (void) {
- if (nf9_pkts_until_template > 0)
- nf9_pkts_until_template = 0;
- }
|