Subject: New implementation of IPFIX/Netflow v9 for supporting VLAN and Mac-address Origin: softflowd-0.9.9-12-g8ea92c3 Upstream-Author: Hitoshi Irino Date: Sun Aug 6 08:17:43 2017 +0900 --- a/common.h +++ b/common.h @@ -45,6 +45,7 @@ #include #include #include +#include #include #include --- a/ipfix.c +++ b/ipfix.c @@ -11,7 +11,7 @@ * 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 + * 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, @@ -29,1048 +29,1173 @@ #include "softflowd.h" #if defined (HAVE_DECL_HTONLL) && !defined (HAVE_DECL_HTOBE64) -#define htobe64 htonll +#define htobe64 htonll #endif -#define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */ +#define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */ /* IPFIX a.k.a. Netflow v.10 */ -struct IPFIX_HEADER { - u_int16_t version, length; - u_int32_t export_time; /* in seconds */ - u_int32_t sequence, od_id; -} __packed; -struct IPFIX_SET_HEADER { - u_int16_t set_id, length; -} __packed; -struct IPFIX_TEMPLATE_RECORD_HEADER { - u_int16_t template_id, count; -} __packed; -struct IPFIX_TEMPLATE_SET_HEADER { - struct IPFIX_SET_HEADER c; - struct IPFIX_TEMPLATE_RECORD_HEADER r; -} __packed; -struct IPFIX_OPTION_TEMPLATE_SET_HEADER { - struct IPFIX_SET_HEADER c; - struct IPFIX_TEMPLATE_RECORD_HEADER r; - u_int16_t scope_count; -} __packed; -struct IPFIX_FIELD_SPECIFIER { - u_int16_t ie, length; -} __packed; -struct IPFIX_VENDOR_FIELD_SPECIFIER { - u_int16_t ie, length; - u_int32_t pen; +struct IPFIX_HEADER +{ + u_int16_t version, length; + u_int32_t export_time; /* in seconds */ + u_int32_t sequence, od_id; +} __packed; +struct NFLOW9_HEADER +{ + u_int16_t version, flows; + u_int32_t uptime_ms; + u_int32_t export_time; /* in seconds */ + u_int32_t sequence, od_id; +} __packed; +struct IPFIX_SET_HEADER +{ + u_int16_t set_id, length; +} __packed; +struct IPFIX_TEMPLATE_RECORD_HEADER +{ + u_int16_t template_id, count; +} __packed; +struct IPFIX_TEMPLATE_SET_HEADER +{ + struct IPFIX_SET_HEADER c; + struct IPFIX_TEMPLATE_RECORD_HEADER r; +} __packed; +struct IPFIX_OPTION_TEMPLATE_SET_HEADER +{ + struct IPFIX_SET_HEADER c; + union + { + struct + { + struct IPFIX_TEMPLATE_RECORD_HEADER r; + u_int16_t scope_count; + } i; + struct + { + u_int16_t template_id; + u_int16_t scope_length; + u_int16_t option_length; + } n; + } u; +} __packed; +struct IPFIX_FIELD_SPECIFIER +{ + u_int16_t ie, length; +} __packed; +struct IPFIX_VENDOR_FIELD_SPECIFIER +{ + u_int16_t ie, length; + u_int32_t pen; } __packed; #define REVERSE_PEN 29305 -#define IPFIX_TEMPLATE_SET_ID 2 -#define IPFIX_OPTION_TEMPLATE_SET_ID 3 -#define IPFIX_MIN_RECORD_SET_ID 256 +#define NFLOW9_TEMPLATE_SET_ID 0 +#define NFLOW9_OPTION_TEMPLATE_SET_ID 1 +#define IPFIX_TEMPLATE_SET_ID 2 +#define IPFIX_OPTION_TEMPLATE_SET_ID 3 +#define IPFIX_MIN_RECORD_SET_ID 256 /* Flowset record ies the we care about */ -#define IPFIX_octetDeltaCount 1 -#define IPFIX_packetDeltaCount 2 +#define IPFIX_octetDeltaCount 1 +#define IPFIX_packetDeltaCount 2 /* ... */ -#define IPFIX_protocolIdentifier 4 -#define IPFIX_ipClassOfService 5 +#define IPFIX_protocolIdentifier 4 +#define IPFIX_ipClassOfService 5 /* ... */ -#define IPFIX_tcpControlBits 6 -#define IPFIX_sourceTransportPort 7 -#define IPFIX_sourceIPv4Address 8 +#define IPFIX_tcpControlBits 6 +#define IPFIX_sourceTransportPort 7 +#define IPFIX_sourceIPv4Address 8 /* ... */ -#define IPFIX_ingressInterface 10 -#define IPFIX_destinationTransportPort 11 -#define IPFIX_destinationIPv4Address 12 +#define IPFIX_ingressInterface 10 +#define IPFIX_destinationTransportPort 11 +#define IPFIX_destinationIPv4Address 12 /* ... */ -#define IPFIX_egressInterface 14 +#define IPFIX_egressInterface 14 /* ... */ -#define IPFIX_flowEndSysUpTime 21 -#define IPFIX_flowStartSysUpTime 22 +#define IPFIX_flowEndSysUpTime 21 +#define IPFIX_flowStartSysUpTime 22 /* ... */ -#define IPFIX_sourceIPv6Address 27 -#define IPFIX_destinationIPv6Address 28 +#define IPFIX_sourceIPv6Address 27 +#define IPFIX_destinationIPv6Address 28 /* ... */ -#define IPFIX_icmpTypeCodeIPv4 32 +#define IPFIX_icmpTypeCodeIPv4 32 /* ... */ +#define NFLOW9_SAMPLING_INTERVAL 34 +#define NFLOW9_SAMPLING_ALGORITHM 35 /* ... */ -#define IPFIX_vlanId 58 +#define IPFIX_sourceMacAddress 56 +#define IPFIX_postDestinationMacAddress 57 +#define IPFIX_vlanId 58 +#define IPFIX_postVlanId 59 -#define IPFIX_ipVersion 60 +#define IPFIX_ipVersion 60 /* ... */ -#define IPFIX_icmpTypeCodeIPv6 139 +#define IPFIX_icmpTypeCodeIPv6 139 /* ... */ -#define IPFIX_meteringProcessId 143 +#define IPFIX_meteringProcessId 143 /* ... */ -#define IPFIX_flowStartSeconds 150 -#define IPFIX_flowEndSeconds 151 -#define IPFIX_flowStartMilliSeconds 152 -#define IPFIX_flowEndMilliSeconds 153 -#define IPFIX_flowStartMicroSeconds 154 -#define IPFIX_flowEndMicroSeconds 155 -#define IPFIX_flowStartNanoSeconds 156 -#define IPFIX_flowEndNanoSeconds 157 +#define IPFIX_flowStartSeconds 150 +#define IPFIX_flowEndSeconds 151 +#define IPFIX_flowStartMilliSeconds 152 +#define IPFIX_flowEndMilliSeconds 153 +#define IPFIX_flowStartMicroSeconds 154 +#define IPFIX_flowEndMicroSeconds 155 +#define IPFIX_flowStartNanoSeconds 156 +#define IPFIX_flowEndNanoSeconds 157 /* ... */ -#define IPFIX_systemInitTimeMilliseconds 160 +#define IPFIX_systemInitTimeMilliseconds 160 /* ... */ -#define PSAMP_selectorAlgorithm 304 -#define PSAMP_samplingPacketInterval 305 -#define PSAMP_samplingPacketSpace 306 +#define PSAMP_selectorAlgorithm 304 +#define PSAMP_samplingPacketInterval 305 +#define PSAMP_samplingPacketSpace 306 + +#define PSAMP_selectorAlgorithm_count 1 + +#define NFLOW9_OPTION_SCOPE_INTERFACE 2 +#define NFLOW9_SAMPLING_ALGORITHM_DETERMINISTIC 1 + +const struct IPFIX_FIELD_SPECIFIER field_v4[] = { + {IPFIX_sourceIPv4Address, 4}, + {IPFIX_destinationIPv4Address, 4} +}; + +const struct IPFIX_FIELD_SPECIFIER field_v6[] = { + {IPFIX_sourceIPv6Address, 16}, + {IPFIX_destinationIPv6Address, 16} +}; + +const struct IPFIX_FIELD_SPECIFIER field_common[] = { + {IPFIX_octetDeltaCount, 4}, + {IPFIX_packetDeltaCount, 4}, + {IPFIX_ingressInterface, 4}, + {IPFIX_egressInterface, 4} +}; + +const struct IPFIX_FIELD_SPECIFIER field_transport[] = { + {IPFIX_sourceTransportPort, 2}, + {IPFIX_destinationTransportPort, 2}, + {IPFIX_protocolIdentifier, 1}, + {IPFIX_tcpControlBits, 1}, + {IPFIX_ipVersion, 1}, + {IPFIX_ipClassOfService, 1} +}; + +const struct IPFIX_FIELD_SPECIFIER field_icmp4[] = { + {IPFIX_icmpTypeCodeIPv4, 2}, + {IPFIX_ipVersion, 1}, + {IPFIX_ipClassOfService, 1} +}; + +const struct IPFIX_FIELD_SPECIFIER field_icmp6[] = { + {IPFIX_icmpTypeCodeIPv6, 2}, + {IPFIX_ipVersion, 1}, + {IPFIX_ipClassOfService, 1} +}; + +const struct IPFIX_FIELD_SPECIFIER field_vlan[] = { + {IPFIX_vlanId, 2}, + {IPFIX_postVlanId, 2} +}; + +const struct IPFIX_FIELD_SPECIFIER field_ether[] = { + {IPFIX_sourceMacAddress, 6}, + {IPFIX_postDestinationMacAddress, 6} +}; + +const struct IPFIX_FIELD_SPECIFIER field_timesec[] = { + {IPFIX_flowStartSeconds, 4}, + {IPFIX_flowEndSeconds, 4} +}; + +const struct IPFIX_FIELD_SPECIFIER field_timemsec[] = { + {IPFIX_flowStartMilliSeconds, 8}, + {IPFIX_flowEndMilliSeconds, 8} +}; + +const struct IPFIX_FIELD_SPECIFIER field_timeusec[] = { + {IPFIX_flowStartMicroSeconds, 8}, + {IPFIX_flowEndMicroSeconds, 8} +}; + +const struct IPFIX_FIELD_SPECIFIER field_timensec[] = { + {IPFIX_flowStartNanoSeconds, 8}, + {IPFIX_flowEndNanoSeconds, 8} +}; + +const struct IPFIX_FIELD_SPECIFIER field_timesysup[] = { + {IPFIX_flowStartSysUpTime, 4}, + {IPFIX_flowEndSysUpTime, 4} +}; + +const struct IPFIX_FIELD_SPECIFIER field_bicommon[] = { + {IPFIX_octetDeltaCount, 4}, + {IPFIX_packetDeltaCount, 4}, + {IPFIX_ipClassOfService, 1} +}; -#define PSAMP_selectorAlgorithm_count 1 +const struct IPFIX_FIELD_SPECIFIER field_bitransport[] = + { {IPFIX_tcpControlBits, 1} }; + +const struct IPFIX_FIELD_SPECIFIER field_biicmp4[] = + { {IPFIX_icmpTypeCodeIPv4, 2} }; + +const struct IPFIX_FIELD_SPECIFIER field_biicmp6[] = + { {IPFIX_icmpTypeCodeIPv6, 2} }; + +const struct IPFIX_FIELD_SPECIFIER field_scope[] = + { {IPFIX_meteringProcessId, 4} }; + +const struct IPFIX_FIELD_SPECIFIER field_option[] = { + {IPFIX_systemInitTimeMilliseconds, 8}, + {PSAMP_samplingPacketInterval, 4}, + {PSAMP_samplingPacketSpace, 4}, + {PSAMP_selectorAlgorithm, 2} +}; + +const struct IPFIX_FIELD_SPECIFIER field_nf9scope[] = + { {NFLOW9_OPTION_SCOPE_INTERFACE, 4} }; + +const struct IPFIX_FIELD_SPECIFIER field_nf9option[] = { + {NFLOW9_SAMPLING_INTERVAL, 4}, + {NFLOW9_SAMPLING_ALGORITHM, 1} +}; /* Stuff pertaining to the templates that softflowd uses */ -#define IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS 14 -#define IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS 2 -#define IPFIX_SOFTFLOWD_TEMPLATE_VENDORRECORDS 5 - -#define IPFIX_SOFTFLOWD_TEMPLATE_NRECORDS \ - IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS + \ - IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS - -#define IPFIX_SOFTFLOWD_TEMPLATE_BIDIRECTION_NRECORDS \ - IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS + \ - IPFIX_SOFTFLOWD_TEMPLATE_VENDORRECORDS + \ - IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS - -struct IPFIX_SOFTFLOWD_TEMPLATE { - struct IPFIX_TEMPLATE_SET_HEADER h; - struct IPFIX_FIELD_SPECIFIER r[IPFIX_SOFTFLOWD_TEMPLATE_NRECORDS]; -} __packed; - -struct IPFIX_SOFTFLOWD_BIDIRECTION_TEMPLATE { - struct IPFIX_TEMPLATE_SET_HEADER h; - struct IPFIX_FIELD_SPECIFIER r[IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS]; - struct IPFIX_VENDOR_FIELD_SPECIFIER v[IPFIX_SOFTFLOWD_TEMPLATE_VENDORRECORDS]; - struct IPFIX_FIELD_SPECIFIER t[IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS]; -} __packed; - -#define IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS 1 -#define IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS 4 -struct IPFIX_SOFTFLOWD_OPTION_TEMPLATE { - struct IPFIX_OPTION_TEMPLATE_SET_HEADER h; - struct IPFIX_FIELD_SPECIFIER s[IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS]; - struct IPFIX_FIELD_SPECIFIER r[IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS]; +#define IPFIX_SOFTFLOWD_TEMPLATE_IPRECORDS \ + sizeof(field_v4) / sizeof(struct IPFIX_FIELD_SPECIFIER) +#define IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS \ + sizeof(field_timesysup) / sizeof(struct IPFIX_FIELD_SPECIFIER) +#define IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS \ + sizeof(field_common) / sizeof(struct IPFIX_FIELD_SPECIFIER) +#define IPFIX_SOFTFLOWD_TEMPLATE_TRANSPORTRECORDS \ + sizeof(field_transport) / sizeof(struct IPFIX_FIELD_SPECIFIER) +#define IPFIX_SOFTFLOWD_TEMPLATE_ICMPRECORDS \ + sizeof(field_icmp4) / sizeof(struct IPFIX_FIELD_SPECIFIER) +#define IPFIX_SOFTFLOWD_TEMPLATE_VLANRECORDS \ + sizeof(field_vlan) / sizeof(struct IPFIX_FIELD_SPECIFIER) +#define IPFIX_SOFTFLOWD_TEMPLATE_ETHERRECORDS \ + sizeof(field_ether) / sizeof(struct IPFIX_FIELD_SPECIFIER) +//#define IPFIX_SOFTFLOWD_TEMPLATE_VENDORRECORDS 5 +#define IPFIX_SOFTFLOWD_TEMPLATE_BICOMMONRECORDS \ + sizeof(field_bicommon) / sizeof(struct IPFIX_FIELD_SPECIFIER) +#define IPFIX_SOFTFLOWD_TEMPLATE_BITRANSPORTRECORDS \ + sizeof(field_bitransport) / sizeof(struct IPFIX_FIELD_SPECIFIER) +#define IPFIX_SOFTFLOWD_TEMPLATE_BIICMPRECORDS \ + sizeof(field_biicmp4) / sizeof(struct IPFIX_FIELD_SPECIFIER) + +#define IPFIX_SOFTFLOWD_TEMPLATE_NRECORDS \ + IPFIX_SOFTFLOWD_TEMPLATE_IPRECORDS + \ + IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS + \ + IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS + \ + IPFIX_SOFTFLOWD_TEMPLATE_TRANSPORTRECORDS + \ + IPFIX_SOFTFLOWD_TEMPLATE_VLANRECORDS + \ + IPFIX_SOFTFLOWD_TEMPLATE_ETHERRECORDS + +#define IPFIX_SOFTFLOWD_TEMPLATE_BI_NRECORDS \ + IPFIX_SOFTFLOWD_TEMPLATE_BICOMMONRECORDS + \ + IPFIX_SOFTFLOWD_TEMPLATE_BITRANSPORTRECORDS + +struct IPFIX_SOFTFLOWD_TEMPLATE +{ + struct IPFIX_TEMPLATE_SET_HEADER h; + struct IPFIX_FIELD_SPECIFIER r[IPFIX_SOFTFLOWD_TEMPLATE_NRECORDS]; + struct IPFIX_VENDOR_FIELD_SPECIFIER + v[IPFIX_SOFTFLOWD_TEMPLATE_BI_NRECORDS]; + u_int16_t data_len, bi_count; +} __packed; + +#define IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS \ + sizeof(field_scope) / sizeof(struct IPFIX_FIELD_SPECIFIER) +#define IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS \ + sizeof(field_option) / sizeof(struct IPFIX_FIELD_SPECIFIER) + +#define NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS \ + sizeof(field_nf9scope) / sizeof(struct IPFIX_FIELD_SPECIFIER) +#define NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS \ + sizeof(field_nf9option) / sizeof(struct IPFIX_FIELD_SPECIFIER) + + +struct IPFIX_SOFTFLOWD_OPTION_TEMPLATE +{ + struct IPFIX_OPTION_TEMPLATE_SET_HEADER h; + struct IPFIX_FIELD_SPECIFIER + s[IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS]; + struct IPFIX_FIELD_SPECIFIER r[IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS]; } __packed; /* softflowd data set */ -struct IPFIX_SOFTFLOWD_DATA_COMMON { - u_int32_t octetDeltaCount, packetDeltaCount; - u_int32_t ingressInterface, egressInterface; - u_int16_t sourceTransportPort, destinationTransportPort; - u_int8_t protocolIdentifier, tcpControlBits, ipVersion, ipClassOfService; - u_int16_t icmpTypeCode, vlanId; -} __packed; - -struct IPFIX_SOFTFLOWD_DATA_BIDIRECTION { - u_int32_t octetDeltaCount, packetDeltaCount; - u_int8_t tcpControlBits, ipClassOfService; - u_int16_t icmpTypeCode; -} __packed; - -union IPFIX_SOFTFLOWD_DATA_TIME { - struct { - u_int32_t start; - u_int32_t end; - } u32; - struct { - u_int64_t start; - u_int64_t end; - } u64; -}; +struct IPFIX_SOFTFLOWD_DATA_COMMON +{ + u_int32_t octetDeltaCount, packetDeltaCount; + u_int32_t ingressInterface, egressInterface; +} __packed; + +struct IPFIX_SOFTFLOWD_DATA_TRANSPORT +{ + u_int16_t sourceTransportPort, destinationTransportPort; + u_int8_t protocolIdentifier, tcpControlBits, ipVersion, ipClassOfService; +} __packed; + +struct IPFIX_SOFTFLOWD_DATA_ICMP +{ + u_int16_t icmpTypeCode; + u_int8_t ipVersion, ipClassOfService; +} __packed; + +struct IPFIX_SOFTFLOWD_DATA_VLAN +{ + u_int16_t vlanId, postVlanId; +} __packed; -struct IPFIX_SOFTFLOWD_DATA_V4 { - u_int32_t sourceIPv4Address, destinationIPv4Address; - struct IPFIX_SOFTFLOWD_DATA_COMMON c; - union IPFIX_SOFTFLOWD_DATA_TIME t; +struct IPFIX_SOFTFLOWD_DATA_ETHER +{ + u_int8_t sourceMacAddress[6], destinationMacAddress[6]; } __packed; -struct IPFIX_SOFTFLOWD_BIDIRECTION_DATA_V4 { - u_int32_t sourceIPv4Address, destinationIPv4Address; - struct IPFIX_SOFTFLOWD_DATA_COMMON c; - struct IPFIX_SOFTFLOWD_DATA_BIDIRECTION b; - union IPFIX_SOFTFLOWD_DATA_TIME t; +struct IPFIX_SOFTFLOWD_DATA_BICOMMON +{ + u_int32_t octetDeltaCount, packetDeltaCount; + u_int8_t ipClassOfService; } __packed; -struct IPFIX_SOFTFLOWD_DATA_V6 { - struct in6_addr sourceIPv6Address, destinationIPv6Address; - struct IPFIX_SOFTFLOWD_DATA_COMMON c; - union IPFIX_SOFTFLOWD_DATA_TIME t; +struct IPFIX_SOFTFLOWD_DATA_BITRANSPORT +{ + u_int8_t tcpControlBits; } __packed; -struct IPFIX_SOFTFLOWD_BIDIRECTION_DATA_V6 { - struct in6_addr sourceIPv6Address, destinationIPv6Address; - struct IPFIX_SOFTFLOWD_DATA_COMMON c; - struct IPFIX_SOFTFLOWD_DATA_BIDIRECTION b; - union IPFIX_SOFTFLOWD_DATA_TIME t; +struct IPFIX_SOFTFLOWD_DATA_BIICMP +{ + u_int16_t icmpTypeCode; } __packed; -struct IPFIX_SOFTFLOWD_OPTION_DATA { - struct IPFIX_SET_HEADER c; - u_int32_t scope_pid; - u_int64_t systemInitTimeMilliseconds; - u_int16_t samplingAlgorithm; - u_int16_t samplingInterval; - u_int32_t samplingSpace; +union IPFIX_SOFTFLOWD_DATA_TIME +{ + struct + { + u_int32_t start; + u_int32_t end; + } u32; + struct + { + u_int64_t start; + u_int64_t end; + } u64; +}; + +struct IPFIX_SOFTFLOWD_DATA_V4ADDR +{ + u_int32_t sourceIPv4Address, destinationIPv4Address; +} __packed; + +struct IPFIX_SOFTFLOWD_DATA_V6ADDR +{ + struct in6_addr sourceIPv6Address, destinationIPv6Address; } __packed; - + +struct IPFIX_SOFTFLOWD_OPTION_DATA +{ + struct IPFIX_SET_HEADER c; + u_int32_t scope_pid; + u_int64_t systemInitTimeMilliseconds; + u_int32_t samplingInterval; + u_int32_t samplingSpace; + u_int16_t samplingAlgorithm; +} __packed; + +struct NFLOW9_SOFTFLOWD_OPTION_DATA +{ + struct IPFIX_SET_HEADER c; + u_int32_t scope_ifidx; + u_int32_t samplingInterval; + u_int8_t samplingAlgorithm; +} __packed; + /* Local data: templates and counters */ -#define IPFIX_SOFTFLOWD_MAX_PACKET_SIZE 512 -#define IPFIX_SOFTFLOWD_V4_TEMPLATE_ID 1024 -#define IPFIX_SOFTFLOWD_V6_TEMPLATE_ID 2048 -#define IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID 256 +#define IPFIX_SOFTFLOWD_MAX_PACKET_SIZE 1428 +#define IPFIX_SOFTFLOWD_V4_TEMPLATE_ID 1024 +#define IPFIX_SOFTFLOWD_ICMPV4_TEMPLATE_ID 1025 +#define IPFIX_SOFTFLOWD_V6_TEMPLATE_ID 2048 +#define IPFIX_SOFTFLOWD_ICMPV6_TEMPLATE_ID 2049 +#define IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID 256 -#define IPFIX_DEFAULT_TEMPLATE_INTERVAL 16 +#define IPFIX_DEFAULT_TEMPLATE_INTERVAL 16 /* ... */ -#define IPFIX_OPTION_SCOPE_SYSTEM 1 -#define IPFIX_OPTION_SCOPE_INTERFACE 2 -#define IPFIX_OPTION_SCOPE_LINECARD 3 -#define IPFIX_OPTION_SCOPE_CACHE 4 -#define IPFIX_OPTION_SCOPE_TEMPLATE 5 +#define IPFIX_OPTION_SCOPE_SYSTEM 1 +#define IPFIX_OPTION_SCOPE_INTERFACE 2 +#define IPFIX_OPTION_SCOPE_LINECARD 3 +#define IPFIX_OPTION_SCOPE_CACHE 4 +#define IPFIX_OPTION_SCOPE_TEMPLATE 5 /* ... */ -#define IPFIX_SAMPLING_ALGORITHM_DETERMINISTIC 1 -#define IPFIX_SAMPLING_ALGORITHM_RANDOM 2 +#define IPFIX_SAMPLING_ALGORITHM_DETERMINISTIC 1 +#define IPFIX_SAMPLING_ALGORITHM_RANDOM 2 /* ... */ -static struct IPFIX_SOFTFLOWD_TEMPLATE v4_template; -static struct IPFIX_SOFTFLOWD_TEMPLATE v6_template; -static struct IPFIX_SOFTFLOWD_BIDIRECTION_TEMPLATE v4_bidirection_template; -static struct IPFIX_SOFTFLOWD_BIDIRECTION_TEMPLATE v6_bidirection_template; +enum +{ TMPLV4, TMPLICMPV4, TMPLV6, TMPLICMPV6, TMPLMAX }; +static struct IPFIX_SOFTFLOWD_TEMPLATE template[TMPLMAX]; static struct IPFIX_SOFTFLOWD_OPTION_TEMPLATE option_template; static struct IPFIX_SOFTFLOWD_OPTION_DATA option_data; +static struct NFLOW9_SOFTFLOWD_OPTION_DATA nf9opt_data; + static int ipfix_pkts_until_template = -1; +static int +ipfix_init_fields (struct IPFIX_FIELD_SPECIFIER *dst, + u_int * index, + const struct IPFIX_FIELD_SPECIFIER *src, + u_int field_number) +{ + int length = 0; + for (int i = 0; i < field_number; i++) + { + dst[*index + i].ie = htons (src[i].ie); + dst[*index + i].length = htons (src[i].length); + length += src[i].length; + } + *index += field_number; + return length; +} + +static int +ipfix_init_bifields (struct IPFIX_SOFTFLOWD_TEMPLATE *template, + u_int * index, + const struct IPFIX_FIELD_SPECIFIER *fields, + u_int field_number) +{ + int length = 0; + for (int i = 0; i < field_number; i++) + { + template->v[*index + i].ie = htons (fields[i].ie | 0x8000); + template->v[*index + i].length = htons (fields[i].length); + template->v[*index + i].pen = htonl (REVERSE_PEN); + length += fields[i].length; + } + *index += field_number; + return length; +} + +static int +ipfix_init_template_time (struct FLOWTRACKPARAMETERS *param, + struct IPFIX_SOFTFLOWD_TEMPLATE *template, + u_int * index) +{ + int length = 0; + if (param->time_format == 's') + { + length = ipfix_init_fields (template->r, index, + field_timesec, + IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS); + } + else if (param->time_format == 'm') + { + length = ipfix_init_fields (template->r, index, + field_timemsec, + IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS); + } + else if (param->time_format == 'M') + { + length = ipfix_init_fields (template->r, index, + field_timeusec, + IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS); + } + else if (param->time_format == 'n') + { + length = ipfix_init_fields (template->r, index, + field_timensec, + IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS); + } + else + { + length = ipfix_init_fields (template->r, index, + field_timesysup, + IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS); + } + return length; +} + static void -ipfix_init_template(struct FLOWTRACKPARAMETERS *param) +ipfix_init_template_unity (struct FLOWTRACKPARAMETERS *param, + struct IPFIX_SOFTFLOWD_TEMPLATE *template, + u_int template_id, u_int8_t v6_flag, + u_int8_t icmp_flag, u_int8_t bi_flag, + u_int16_t version) { - bzero(&v4_template, sizeof(v4_template)); - v4_template.h.c.set_id = htons(IPFIX_TEMPLATE_SET_ID); - v4_template.h.c.length = htons(sizeof(v4_template)); - v4_template.h.r.template_id = htons(IPFIX_SOFTFLOWD_V4_TEMPLATE_ID); - v4_template.h.r.count = htons(IPFIX_SOFTFLOWD_TEMPLATE_NRECORDS); - v4_template.r[0].ie = htons(IPFIX_sourceIPv4Address); - v4_template.r[0].length = htons(4); - v4_template.r[1].ie = htons(IPFIX_destinationIPv4Address); - v4_template.r[1].length = htons(4); - v4_template.r[2].ie = htons(IPFIX_octetDeltaCount); - v4_template.r[2].length = htons(4); - v4_template.r[3].ie = htons(IPFIX_packetDeltaCount); - v4_template.r[3].length = htons(4); - v4_template.r[4].ie = htons(IPFIX_ingressInterface); - v4_template.r[4].length = htons(4); - v4_template.r[5].ie = htons(IPFIX_egressInterface); - v4_template.r[5].length = htons(4); - v4_template.r[6].ie = htons(IPFIX_sourceTransportPort); - v4_template.r[6].length = htons(2); - v4_template.r[7].ie = htons(IPFIX_destinationTransportPort); - v4_template.r[7].length = htons(2); - v4_template.r[8].ie = htons(IPFIX_protocolIdentifier); - v4_template.r[8].length = htons(1); - v4_template.r[9].ie = htons(IPFIX_tcpControlBits); - v4_template.r[9].length = htons(1); - v4_template.r[10].ie = htons(IPFIX_ipVersion); - v4_template.r[10].length = htons(1); - v4_template.r[11].ie = htons(IPFIX_ipClassOfService); - v4_template.r[11].length = htons(1); - v4_template.r[12].ie = htons(IPFIX_icmpTypeCodeIPv4); - v4_template.r[12].length = htons(2); - v4_template.r[13].ie = htons(IPFIX_vlanId); - v4_template.r[13].length = htons(2); - if (param->time_format == 's') { - v4_template.r[14].ie = htons(IPFIX_flowStartSeconds); - v4_template.r[14].length = htons(sizeof(u_int32_t)); - v4_template.r[15].ie = htons(IPFIX_flowEndSeconds); - v4_template.r[15].length = htons(sizeof(u_int32_t)); - } else if (param->time_format == 'm') { - v4_template.r[14].ie = htons(IPFIX_flowStartMilliSeconds); - v4_template.r[14].length = htons(sizeof(u_int64_t)); - v4_template.r[15].ie = htons(IPFIX_flowEndMilliSeconds); - v4_template.r[15].length = htons(sizeof(u_int64_t)); - } else if (param->time_format == 'M') { - v4_template.r[14].ie = htons(IPFIX_flowStartMicroSeconds); - v4_template.r[14].length = htons(sizeof(u_int64_t)); - v4_template.r[15].ie = htons(IPFIX_flowEndMicroSeconds); - v4_template.r[15].length = htons(sizeof(u_int64_t)); - } else if (param->time_format == 'n') { - v4_template.r[14].ie = htons(IPFIX_flowStartNanoSeconds); - v4_template.r[14].length = htons(sizeof(u_int64_t)); - v4_template.r[15].ie = htons(IPFIX_flowEndNanoSeconds); - v4_template.r[15].length = htons(sizeof(u_int64_t)); - } else { - v4_template.r[14].ie = htons(IPFIX_flowStartSysUpTime); - v4_template.r[14].length = htons(sizeof(u_int32_t)); - v4_template.r[15].ie = htons(IPFIX_flowEndSysUpTime); - v4_template.r[15].length = htons(sizeof(u_int32_t)); - } - - bzero(&v6_template, sizeof(v6_template)); - v6_template.h.c.set_id = htons(IPFIX_TEMPLATE_SET_ID); - v6_template.h.c.length = htons(sizeof(v6_template)); - v6_template.h.r.template_id = htons(IPFIX_SOFTFLOWD_V6_TEMPLATE_ID); - v6_template.h.r.count = htons(IPFIX_SOFTFLOWD_TEMPLATE_NRECORDS); - v6_template.r[0].ie = htons(IPFIX_sourceIPv6Address); - v6_template.r[0].length = htons(16); - v6_template.r[1].ie = htons(IPFIX_destinationIPv6Address); - v6_template.r[1].length = htons(16); - v6_template.r[2].ie = htons(IPFIX_octetDeltaCount); - v6_template.r[2].length = htons(4); - v6_template.r[3].ie = htons(IPFIX_packetDeltaCount); - v6_template.r[3].length = htons(4); - v6_template.r[4].ie = htons(IPFIX_ingressInterface); - v6_template.r[4].length = htons(4); - v6_template.r[5].ie = htons(IPFIX_egressInterface); - v6_template.r[5].length = htons(4); - v6_template.r[6].ie = htons(IPFIX_sourceTransportPort); - v6_template.r[6].length = htons(2); - v6_template.r[7].ie = htons(IPFIX_destinationTransportPort); - v6_template.r[7].length = htons(2); - v6_template.r[8].ie = htons(IPFIX_protocolIdentifier); - v6_template.r[8].length = htons(1); - v6_template.r[9].ie = htons(IPFIX_tcpControlBits); - v6_template.r[9].length = htons(1); - v6_template.r[10].ie = htons(IPFIX_ipVersion); - v6_template.r[10].length = htons(1); - v6_template.r[11].ie = htons(IPFIX_ipClassOfService); - v6_template.r[11].length = htons(1); - v6_template.r[12].ie = htons(IPFIX_icmpTypeCodeIPv6); - v6_template.r[12].length = htons(2); - v6_template.r[13].ie = htons(IPFIX_vlanId); - v6_template.r[13].length = htons(2); - if (param->time_format == 's') { - v6_template.r[14].ie = htons(IPFIX_flowStartSeconds); - v6_template.r[14].length = htons(sizeof(u_int32_t)); - v6_template.r[15].ie = htons(IPFIX_flowEndSeconds); - v6_template.r[15].length = htons(sizeof(u_int32_t)); - } else if (param->time_format == 'm') { - v6_template.r[14].ie = htons(IPFIX_flowStartMilliSeconds); - v6_template.r[14].length = htons(sizeof(u_int64_t)); - v6_template.r[15].ie = htons(IPFIX_flowEndMilliSeconds); - v6_template.r[15].length = htons(sizeof(u_int64_t)); - } else if (param->time_format == 'M') { - v6_template.r[14].ie = htons(IPFIX_flowStartMicroSeconds); - v6_template.r[14].length = htons(sizeof(u_int64_t)); - v6_template.r[15].ie = htons(IPFIX_flowEndMicroSeconds); - v6_template.r[15].length = htons(sizeof(u_int64_t)); - } else if (param->time_format == 'n') { - v6_template.r[14].ie = htons(IPFIX_flowStartNanoSeconds); - v6_template.r[14].length = htons(sizeof(u_int64_t)); - v6_template.r[15].ie = htons(IPFIX_flowEndNanoSeconds); - v6_template.r[15].length = htons(sizeof(u_int64_t)); - } else { - v6_template.r[14].ie = htons(IPFIX_flowStartSysUpTime); - v6_template.r[14].length = htons(sizeof(u_int32_t)); - v6_template.r[15].ie = htons(IPFIX_flowEndSysUpTime); - v6_template.r[15].length = htons(sizeof(u_int32_t)); - } + u_int index = 0, bi_index = 0, length = 0; + bzero (template, sizeof (*template)); + template->h.c.set_id = htons (version == 10 ? + IPFIX_TEMPLATE_SET_ID : + NFLOW9_TEMPLATE_SET_ID); + template->h.r.template_id = htons (template_id); + if (v6_flag) + { + length += ipfix_init_fields (template->r, &index, + field_v6, + IPFIX_SOFTFLOWD_TEMPLATE_IPRECORDS); + } + else + { + length += ipfix_init_fields (template->r, &index, + field_v4, + IPFIX_SOFTFLOWD_TEMPLATE_IPRECORDS); + } + length += ipfix_init_template_time (param, template, &index); + length += ipfix_init_fields (template->r, &index, + field_common, + IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS); + if (icmp_flag) + { + if (v6_flag) + { + length += ipfix_init_fields (template->r, &index, + field_icmp6, + IPFIX_SOFTFLOWD_TEMPLATE_ICMPRECORDS); + } + else + { + length += ipfix_init_fields (template->r, &index, + field_icmp4, + IPFIX_SOFTFLOWD_TEMPLATE_ICMPRECORDS); + } + } + else + { + length += ipfix_init_fields (template->r, &index, + field_transport, + IPFIX_SOFTFLOWD_TEMPLATE_TRANSPORTRECORDS); + } + if (param->track_level >= TRACK_FULL_VLAN) + { + length += ipfix_init_fields (template->r, &index, + field_vlan, + IPFIX_SOFTFLOWD_TEMPLATE_VLANRECORDS); + } + if (param->track_level >= TRACK_FULL_VLAN_ETHER) + { + length += ipfix_init_fields (template->r, &index, + field_ether, + IPFIX_SOFTFLOWD_TEMPLATE_ETHERRECORDS); + } + if (bi_flag) + { + length += + ipfix_init_bifields (template, &bi_index, + field_bicommon, + IPFIX_SOFTFLOWD_TEMPLATE_BICOMMONRECORDS); + if (icmp_flag) + { + if (v6_flag) + { + length += + ipfix_init_bifields (template, &bi_index, + field_biicmp6, + IPFIX_SOFTFLOWD_TEMPLATE_BIICMPRECORDS); + } + else + { + length += + ipfix_init_bifields (template, &bi_index, + field_biicmp4, + IPFIX_SOFTFLOWD_TEMPLATE_BIICMPRECORDS); + } + } + else + { + length += + ipfix_init_bifields (template, &bi_index, + field_bitransport, + IPFIX_SOFTFLOWD_TEMPLATE_BITRANSPORTRECORDS); + + } + } + template->bi_count = bi_index; + template->h.r.count = htons (index + bi_index); + template->h.c.length = + htons (sizeof (struct IPFIX_TEMPLATE_SET_HEADER) + + index * sizeof (struct IPFIX_FIELD_SPECIFIER) + + bi_index * sizeof (struct IPFIX_VENDOR_FIELD_SPECIFIER)); + template->data_len = length; } static void -ipfix_init_template_bidirection(struct FLOWTRACKPARAMETERS *param) +ipfix_init_template (struct FLOWTRACKPARAMETERS *param, + u_int8_t bi_flag, u_int16_t version) { - bzero(&v4_bidirection_template, sizeof(v4_bidirection_template)); - v4_bidirection_template.h.c.set_id = htons(IPFIX_TEMPLATE_SET_ID); - v4_bidirection_template.h.c.length = htons(sizeof(v4_bidirection_template)); - v4_bidirection_template.h.r.template_id = htons(IPFIX_SOFTFLOWD_V4_TEMPLATE_ID); - v4_bidirection_template.h.r.count = htons(IPFIX_SOFTFLOWD_TEMPLATE_BIDIRECTION_NRECORDS); - v4_bidirection_template.r[0].ie = htons(IPFIX_sourceIPv4Address); - v4_bidirection_template.r[0].length = htons(4); - v4_bidirection_template.r[1].ie = htons(IPFIX_destinationIPv4Address); - v4_bidirection_template.r[1].length = htons(4); - v4_bidirection_template.r[2].ie = htons(IPFIX_octetDeltaCount); - v4_bidirection_template.r[2].length = htons(4); - v4_bidirection_template.r[3].ie = htons(IPFIX_packetDeltaCount); - v4_bidirection_template.r[3].length = htons(4); - v4_bidirection_template.r[4].ie = htons(IPFIX_ingressInterface); - v4_bidirection_template.r[4].length = htons(4); - v4_bidirection_template.r[5].ie = htons(IPFIX_egressInterface); - v4_bidirection_template.r[5].length = htons(4); - v4_bidirection_template.r[6].ie = htons(IPFIX_sourceTransportPort); - v4_bidirection_template.r[6].length = htons(2); - v4_bidirection_template.r[7].ie = htons(IPFIX_destinationTransportPort); - v4_bidirection_template.r[7].length = htons(2); - v4_bidirection_template.r[8].ie = htons(IPFIX_protocolIdentifier); - v4_bidirection_template.r[8].length = htons(1); - v4_bidirection_template.r[9].ie = htons(IPFIX_tcpControlBits); - v4_bidirection_template.r[9].length = htons(1); - v4_bidirection_template.r[10].ie = htons(IPFIX_ipVersion); - v4_bidirection_template.r[10].length = htons(1); - v4_bidirection_template.r[11].ie = htons(IPFIX_ipClassOfService); - v4_bidirection_template.r[11].length = htons(1); - v4_bidirection_template.r[12].ie = htons(IPFIX_icmpTypeCodeIPv4); - v4_bidirection_template.r[12].length = htons(2); - v4_bidirection_template.r[13].ie = htons(IPFIX_vlanId); - v4_bidirection_template.r[13].length = htons(2); - v4_bidirection_template.v[0].ie = htons(IPFIX_octetDeltaCount | 0x8000); - v4_bidirection_template.v[0].length = htons(4); - v4_bidirection_template.v[0].pen = htonl(REVERSE_PEN); - v4_bidirection_template.v[1].ie = htons(IPFIX_packetDeltaCount | 0x8000); - v4_bidirection_template.v[1].length = htons(4); - v4_bidirection_template.v[1].pen = htonl(REVERSE_PEN); - v4_bidirection_template.v[2].ie = htons(IPFIX_tcpControlBits | 0x8000); - v4_bidirection_template.v[2].length = htons(1); - v4_bidirection_template.v[2].pen = htonl(REVERSE_PEN); - v4_bidirection_template.v[3].ie = htons(IPFIX_ipClassOfService | 0x8000); - v4_bidirection_template.v[3].length = htons(1); - v4_bidirection_template.v[3].pen = htonl(REVERSE_PEN); - v4_bidirection_template.v[4].ie = htons(IPFIX_icmpTypeCodeIPv4 | 0x8000); - v4_bidirection_template.v[4].length = htons(2); - v4_bidirection_template.v[4].pen = htonl(REVERSE_PEN); - if (param->time_format == 's') { - v4_bidirection_template.t[0].ie = htons(IPFIX_flowStartSeconds); - v4_bidirection_template.t[0].length = htons(sizeof(u_int32_t)); - v4_bidirection_template.t[1].ie = htons(IPFIX_flowEndSeconds); - v4_bidirection_template.t[1].length = htons(sizeof(u_int32_t)); - } else if (param->time_format == 'm') { - v4_bidirection_template.t[0].ie = htons(IPFIX_flowStartMilliSeconds); - v4_bidirection_template.t[0].length = htons(sizeof(u_int64_t)); - v4_bidirection_template.t[1].ie = htons(IPFIX_flowEndMilliSeconds); - v4_bidirection_template.t[1].length = htons(sizeof(u_int64_t)); - } else if (param->time_format == 'M') { - v4_bidirection_template.t[0].ie = htons(IPFIX_flowStartMicroSeconds); - v4_bidirection_template.t[0].length = htons(sizeof(u_int64_t)); - v4_bidirection_template.t[1].ie = htons(IPFIX_flowEndMicroSeconds); - v4_bidirection_template.t[1].length = htons(sizeof(u_int64_t)); - } else if (param->time_format == 'n') { - v4_bidirection_template.t[0].ie = htons(IPFIX_flowStartNanoSeconds); - v4_bidirection_template.t[0].length = htons(sizeof(u_int64_t)); - v4_bidirection_template.t[1].ie = htons(IPFIX_flowEndNanoSeconds); - v4_bidirection_template.t[1].length = htons(sizeof(u_int64_t)); - } else { - v4_bidirection_template.t[0].ie = htons(IPFIX_flowStartSysUpTime); - v4_bidirection_template.t[0].length = htons(sizeof(u_int32_t)); - v4_bidirection_template.t[1].ie = htons(IPFIX_flowEndSysUpTime); - v4_bidirection_template.t[1].length = htons(sizeof(u_int32_t)); - } - - bzero(&v6_bidirection_template, sizeof(v6_bidirection_template)); - v6_bidirection_template.h.c.set_id = htons(IPFIX_TEMPLATE_SET_ID); - v6_bidirection_template.h.c.length = htons(sizeof(v6_bidirection_template)); - v6_bidirection_template.h.r.template_id = htons(IPFIX_SOFTFLOWD_V6_TEMPLATE_ID); - v6_bidirection_template.h.r.count = htons(IPFIX_SOFTFLOWD_TEMPLATE_BIDIRECTION_NRECORDS); - v6_bidirection_template.r[0].ie = htons(IPFIX_sourceIPv6Address); - v6_bidirection_template.r[0].length = htons(16); - v6_bidirection_template.r[1].ie = htons(IPFIX_destinationIPv6Address); - v6_bidirection_template.r[1].length = htons(16); - v6_bidirection_template.r[2].ie = htons(IPFIX_octetDeltaCount); - v6_bidirection_template.r[2].length = htons(4); - v6_bidirection_template.r[3].ie = htons(IPFIX_packetDeltaCount); - v6_bidirection_template.r[3].length = htons(4); - v6_bidirection_template.r[4].ie = htons(IPFIX_ingressInterface); - v6_bidirection_template.r[4].length = htons(4); - v6_bidirection_template.r[5].ie = htons(IPFIX_egressInterface); - v6_bidirection_template.r[5].length = htons(4); - v6_bidirection_template.r[6].ie = htons(IPFIX_sourceTransportPort); - v6_bidirection_template.r[6].length = htons(2); - v6_bidirection_template.r[7].ie = htons(IPFIX_destinationTransportPort); - v6_bidirection_template.r[7].length = htons(2); - v6_bidirection_template.r[8].ie = htons(IPFIX_protocolIdentifier); - v6_bidirection_template.r[8].length = htons(1); - v6_bidirection_template.r[9].ie = htons(IPFIX_tcpControlBits); - v6_bidirection_template.r[9].length = htons(1); - v6_bidirection_template.r[10].ie = htons(IPFIX_ipVersion); - v6_bidirection_template.r[10].length = htons(1); - v6_bidirection_template.r[11].ie = htons(IPFIX_ipClassOfService); - v6_bidirection_template.r[11].length = htons(1); - v6_bidirection_template.r[12].ie = htons(IPFIX_icmpTypeCodeIPv6); - v6_bidirection_template.r[12].length = htons(2); - v6_bidirection_template.r[13].ie = htons(IPFIX_vlanId); - v6_bidirection_template.r[13].length = htons(2); - v6_bidirection_template.v[0].ie = htons(IPFIX_octetDeltaCount | 0x8000); - v6_bidirection_template.v[0].length = htons(4); - v6_bidirection_template.v[0].pen = htonl(REVERSE_PEN); - v6_bidirection_template.v[1].ie = htons(IPFIX_packetDeltaCount | 0x8000); - v6_bidirection_template.v[1].length = htons(4); - v6_bidirection_template.v[1].pen = htonl(REVERSE_PEN); - v6_bidirection_template.v[2].ie = htons(IPFIX_tcpControlBits | 0x8000); - v6_bidirection_template.v[2].length = htons(1); - v6_bidirection_template.v[2].pen = htonl(REVERSE_PEN); - v6_bidirection_template.v[3].ie = htons(IPFIX_ipClassOfService | 0x8000); - v6_bidirection_template.v[3].length = htons(1); - v6_bidirection_template.v[3].pen = htonl(REVERSE_PEN); - v6_bidirection_template.v[4].ie = htons(IPFIX_icmpTypeCodeIPv6 | 0x8000); - v6_bidirection_template.v[4].length = htons(2); - v6_bidirection_template.v[4].pen = htonl(REVERSE_PEN); - if (param->time_format == 's') { - v6_bidirection_template.t[0].ie = htons(IPFIX_flowStartSeconds); - v6_bidirection_template.t[0].length = htons(sizeof(u_int32_t)); - v6_bidirection_template.t[1].ie = htons(IPFIX_flowEndSeconds); - v6_bidirection_template.t[1].length = htons(sizeof(u_int32_t)); - } else if (param->time_format == 'm') { - v6_bidirection_template.t[0].ie = htons(IPFIX_flowStartMilliSeconds); - v6_bidirection_template.t[0].length = htons(sizeof(u_int64_t)); - v6_bidirection_template.t[1].ie = htons(IPFIX_flowEndMilliSeconds); - v6_bidirection_template.t[1].length = htons(sizeof(u_int64_t)); - } else if (param->time_format == 'M') { - v6_bidirection_template.t[0].ie = htons(IPFIX_flowStartMicroSeconds); - v6_bidirection_template.t[0].length = htons(sizeof(u_int64_t)); - v6_bidirection_template.t[1].ie = htons(IPFIX_flowEndMicroSeconds); - v6_bidirection_template.t[1].length = htons(sizeof(u_int64_t)); - } else if (param->time_format == 'n') { - v6_bidirection_template.t[0].ie = htons(IPFIX_flowStartNanoSeconds); - v6_bidirection_template.t[0].length = htons(sizeof(u_int64_t)); - v6_bidirection_template.t[1].ie = htons(IPFIX_flowEndNanoSeconds); - v6_bidirection_template.t[1].length = htons(sizeof(u_int64_t)); - } else { - v6_bidirection_template.t[0].ie = htons(IPFIX_flowStartSysUpTime); - v6_bidirection_template.t[0].length = htons(sizeof(u_int32_t)); - v6_bidirection_template.t[1].ie = htons(IPFIX_flowEndSysUpTime); - v6_bidirection_template.t[1].length = htons(sizeof(u_int32_t)); - } + u_int8_t v6_flag = 0, icmp_flag = 0; + u_int16_t template_id = 0; + for (int i = 0; i < TMPLMAX; i++) + { + switch (i) + { + case TMPLV4: + v6_flag = 0; + icmp_flag = 0; + template_id = IPFIX_SOFTFLOWD_V4_TEMPLATE_ID; + break; + case TMPLICMPV4: + v6_flag = 0; + icmp_flag = 1; + template_id = IPFIX_SOFTFLOWD_ICMPV4_TEMPLATE_ID; + break; + case TMPLV6: + v6_flag = 1; + icmp_flag = 0; + template_id = IPFIX_SOFTFLOWD_V6_TEMPLATE_ID; + break; + case TMPLICMPV6: + v6_flag = 1; + icmp_flag = 1; + template_id = IPFIX_SOFTFLOWD_ICMPV6_TEMPLATE_ID; + break; + } + ipfix_init_template_unity (param, &template[i], + template_id, v6_flag, + icmp_flag, bi_flag, version); + } } +static void +nflow9_init_option (u_int16_t ifidx, struct OPTION *option) +{ + u_int scope_index = 0, option_index = 0; + u_int16_t scope_len = + NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS * + sizeof (struct IPFIX_FIELD_SPECIFIER); + u_int16_t opt_len = + NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS * + sizeof (struct IPFIX_FIELD_SPECIFIER); + + bzero (&option_template, sizeof (option_template)); + option_template.h.c.set_id = htons (NFLOW9_OPTION_TEMPLATE_SET_ID); + option_template.h.c.length = + htons (sizeof (option_template.h) + scope_len + opt_len); + option_template.h.u.n.template_id + = htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID); + option_template.h.u.n.scope_length = htons (scope_len); + option_template.h.u.n.option_length = htons (opt_len); + ipfix_init_fields (option_template.s, &scope_index, + field_nf9scope, + NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS); + ipfix_init_fields (option_template.r, &option_index, + field_nf9option, + NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS); + bzero (&nf9opt_data, sizeof (nf9opt_data)); + nf9opt_data.c.set_id = htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID); + nf9opt_data.c.length = htons (sizeof (nf9opt_data)); + nf9opt_data.scope_ifidx = htonl (ifidx); + nf9opt_data.samplingInterval = + htonl (option->sample > 1 ? option->sample : 1); + nf9opt_data.samplingAlgorithm = NFLOW9_SAMPLING_ALGORITHM_DETERMINISTIC; +} static void -ipfix_init_option(struct timeval *system_boot_time, struct OPTION *option) { - bzero(&option_template, sizeof(option_template)); - option_template.h.c.set_id = htons(IPFIX_OPTION_TEMPLATE_SET_ID); - option_template.h.c.length = htons(sizeof(option_template)); - option_template.h.r.template_id = htons(IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID); - option_template.h.r.count = htons(IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS + IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS); - option_template.h.scope_count = htons(IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS); - option_template.s[0].ie = htons(IPFIX_meteringProcessId); - option_template.s[0].length = htons(sizeof(option_data.scope_pid)); - option_template.r[0].ie = htons(IPFIX_systemInitTimeMilliseconds); - option_template.r[0].length = htons(sizeof(option_data.systemInitTimeMilliseconds)); - option_template.r[1].ie = htons(PSAMP_selectorAlgorithm); - option_template.r[1].length = htons(sizeof(option_data.samplingAlgorithm)); - option_template.r[2].ie = htons(PSAMP_samplingPacketInterval); - option_template.r[2].length = htons(sizeof(option_data.samplingInterval)); - option_template.r[3].ie = htons(PSAMP_samplingPacketSpace); - option_template.r[3].length = htons(sizeof(option_data.samplingSpace)); - - bzero(&option_data, sizeof(option_data)); - option_data.c.set_id = htons(IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID); - option_data.c.length = htons(sizeof(option_data)); - option_data.scope_pid = htonl((u_int32_t)option->meteringProcessId); +ipfix_init_option (struct timeval *system_boot_time, struct OPTION *option) +{ + u_int scope_index = 0, option_index = 0; + bzero (&option_template, sizeof (option_template)); + option_template.h.c.set_id = htons (IPFIX_OPTION_TEMPLATE_SET_ID); + option_template.h.c.length = htons (sizeof (option_template)); + option_template.h.u.i.r.template_id = + htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID); + option_template.h.u.i.r.count = + htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS + + IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS); + option_template.h.u.i.scope_count = + htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS); + + ipfix_init_fields (option_template.s, &scope_index, + field_scope, + IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS); + ipfix_init_fields (option_template.r, &option_index, field_option, + IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS); + + bzero (&option_data, sizeof (option_data)); + option_data.c.set_id = htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID); + option_data.c.length = htons (sizeof (option_data)); + option_data.scope_pid = htonl ((u_int32_t) option->meteringProcessId); #if defined(htobe64) || defined(HAVE_DECL_HTOBE64) - option_data.systemInitTimeMilliseconds = htobe64((u_int64_t)system_boot_time->tv_sec * 1000 + (u_int64_t)system_boot_time->tv_usec / 1000); + option_data.systemInitTimeMilliseconds = + htobe64 ((u_int64_t) system_boot_time->tv_sec * 1000 + + (u_int64_t) system_boot_time->tv_usec / 1000); #endif - option_data.samplingAlgorithm = htons(PSAMP_selectorAlgorithm_count); - option_data.samplingInterval = htons(1); - option_data.samplingSpace = htonl(option->sample > 0 ? option->sample - 1 : 0); + option_data.samplingAlgorithm = htons (PSAMP_selectorAlgorithm_count); + option_data.samplingInterval = htonl (1); + option_data.samplingSpace = + htonl (option->sample > 0 ? option->sample - 1 : 0); } static int -ipfix_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, - struct FLOWTRACKPARAMETERS *param) -{ - union { - struct IPFIX_SOFTFLOWD_DATA_V4 d4; - struct IPFIX_SOFTFLOWD_DATA_V6 d6; - } d[2]; - struct IPFIX_SOFTFLOWD_DATA_COMMON *dc[2]; - union IPFIX_SOFTFLOWD_DATA_TIME *dt[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 IPFIX_SOFTFLOWD_DATA_V4); - if (!(param->time_format == 'm' || param->time_format == 'M' || param->time_format == 'n')) { - freclen -= (sizeof(u_int64_t) - sizeof(u_int32_t)) * 2; - } - memcpy(&d[0].d4.sourceIPv4Address, &flow->addr[0].v4, 4); - memcpy(&d[0].d4.destinationIPv4Address, &flow->addr[1].v4, 4); - memcpy(&d[1].d4.sourceIPv4Address, &flow->addr[1].v4, 4); - memcpy(&d[1].d4.destinationIPv4Address, &flow->addr[0].v4, 4); - dc[0] = &d[0].d4.c; - dc[1] = &d[1].d4.c; - dt[0] = &d[0].d4.t; - dt[1] = &d[1].d4.t; - dc[0]->ipVersion = dc[1]->ipVersion = 4; - break; - case AF_INET6: - freclen = sizeof(struct IPFIX_SOFTFLOWD_DATA_V6); - if (!(param->time_format == 'm' || param->time_format == 'M' || param->time_format == 'n')) { - freclen -= (sizeof(u_int64_t) - sizeof(u_int32_t)) * 2; - } - memcpy(&d[0].d6.sourceIPv6Address, &flow->addr[0].v6, 16); - memcpy(&d[0].d6.destinationIPv6Address, &flow->addr[1].v6, 16); - memcpy(&d[1].d6.sourceIPv6Address, &flow->addr[1].v6, 16); - memcpy(&d[1].d6.destinationIPv6Address, &flow->addr[0].v6, 16); - dc[0] = &d[0].d6.c; - dc[1] = &d[1].d6.c; - dt[0] = &d[0].d6.t; - dt[1] = &d[1].d6.t; - dc[0]->ipVersion = dc[1]->ipVersion = 6; - break; - default: - return (-1); - } - - if (param->time_format == 's') { - dt[0]->u32.start = dt[1]->u32.start = - htonl(flow->flow_start.tv_sec); - dt[0]->u32.end = dt[1]->u32.end = - htonl(flow->flow_last.tv_sec); - } +copy_data_time (union IPFIX_SOFTFLOWD_DATA_TIME *dt, + const struct FLOW *flow, + const struct timeval *system_boot_time, + struct FLOWTRACKPARAMETERS *param) +{ + int length = (param->time_format == 'm' || param->time_format == 'M' + || param->time_format == 'n') ? 16 : 8; + if (dt == NULL) + return -1; + + if (param->time_format == 's') + { + dt->u32.start = htonl (flow->flow_start.tv_sec); + dt->u32.end = htonl (flow->flow_last.tv_sec); + } #if defined(htobe64) || defined(HAVE_DECL_HTOBE64) - else if (param->time_format == 'm') { /* milliseconds */ - dt[0]->u64.start = dt[1]->u64.start = - htobe64((u_int64_t)flow->flow_start.tv_sec * 1000 + (u_int64_t)flow->flow_start.tv_usec / 1000); - dt[0]->u64.end = dt[1]->u64.end = - htobe64((u_int64_t)flow->flow_last.tv_sec * 1000 + (u_int64_t)flow->flow_last.tv_usec / 1000); - } else if (param->time_format == 'M') { /* microseconds */ - dt[0]->u64.start = dt[1]->u64.start = - htobe64(((u_int64_t)flow->flow_start.tv_sec + JAN_1970) << 32 | (u_int32_t)(((u_int64_t)flow->flow_start.tv_usec << 32) / 1e6)); - dt[0]->u64.end = dt[1]->u64.end = - htobe64(((u_int64_t)flow->flow_last.tv_sec + JAN_1970) << 32 | (u_int32_t)(((u_int64_t)flow->flow_last.tv_usec << 32) / 1e6)); - } else if (param->time_format == 'n') { /* nanoseconds */ - dt[0]->u64.start = dt[1]->u64.start = - htobe64(((u_int64_t)flow->flow_start.tv_sec + JAN_1970) << 32 | (u_int32_t)(((u_int64_t)flow->flow_start.tv_usec << 32) / 1e9)); - dt[0]->u64.end = dt[1]->u64.end = - htobe64(((u_int64_t)flow->flow_last.tv_sec + JAN_1970) << 32 | (u_int32_t)(((u_int64_t)flow->flow_last.tv_usec << 32) / 1e9)); - } + else if (param->time_format == 'm') + { /* milliseconds */ + dt->u64.start = + htobe64 ((u_int64_t) flow->flow_start.tv_sec * 1000 + + (u_int64_t) flow->flow_start.tv_usec / 1000); + dt->u64.end = + htobe64 ((u_int64_t) flow->flow_last.tv_sec * 1000 + + (u_int64_t) flow->flow_last.tv_usec / 1000); + } + else if (param->time_format == 'M') + { /* microseconds */ + dt->u64.start = + htobe64 (((u_int64_t) flow->flow_start.tv_sec + + JAN_1970) << 32 | (u_int32_t) (((u_int64_t) flow-> + flow_start. + tv_usec << 32) / + 1e6)); + dt->u64.end = + htobe64 (((u_int64_t) flow->flow_last.tv_sec + + JAN_1970) << 32 | (u_int32_t) (((u_int64_t) flow-> + flow_last. + tv_usec << 32) / + 1e6)); + } + else if (param->time_format == 'n') + { /* nanoseconds */ + dt->u64.start = + htobe64 (((u_int64_t) flow->flow_start.tv_sec + + JAN_1970) << 32 | (u_int32_t) (((u_int64_t) flow-> + flow_start. + tv_usec << 32) / + 1e9)); + dt->u64.end = + htobe64 (((u_int64_t) flow->flow_last.tv_sec + + JAN_1970) << 32 | (u_int32_t) (((u_int64_t) flow-> + flow_last. + tv_usec << 32) / + 1e9)); + } #endif - else { - dt[0]->u32.start = dt[1]->u32.start = - htonl(timeval_sub_ms(&flow->flow_start, system_boot_time)); - dt[0]->u32.end = dt[1]->u32.end = - htonl(timeval_sub_ms(&flow->flow_last, system_boot_time)); - } - dc[0]->octetDeltaCount = htonl(flow->octets[0]); - dc[1]->octetDeltaCount = htonl(flow->octets[1]); - dc[0]->packetDeltaCount = htonl(flow->packets[0]); - dc[1]->packetDeltaCount = htonl(flow->packets[1]); - dc[0]->ingressInterface = dc[0]->egressInterface = htonl(ifidx); - dc[1]->ingressInterface = dc[1]->egressInterface = htonl(ifidx); - dc[0]->sourceTransportPort = dc[1]->destinationTransportPort = flow->port[0]; - dc[1]->sourceTransportPort = dc[0]->destinationTransportPort = flow->port[1]; - dc[0]->protocolIdentifier = dc[1]->protocolIdentifier = flow->protocol; - dc[0]->tcpControlBits = flow->tcp_flags[0]; - dc[1]->tcpControlBits = flow->tcp_flags[1]; - dc[0]->ipClassOfService = flow->tos[0]; - dc[1]->ipClassOfService = flow->tos[1]; - if (flow->protocol == IPPROTO_ICMP || flow->protocol == IPPROTO_ICMPV6) { - dc[0]->icmpTypeCode = dc[0]->destinationTransportPort; - dc[1]->icmpTypeCode = dc[1]->destinationTransportPort; - } - dc[0]->vlanId = dc[1]->vlanId = htons(flow->vlanid); - - 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++; - } + else + { + dt->u32.start = + htonl (timeval_sub_ms (&flow->flow_start, system_boot_time)); + dt->u32.end = + htonl (timeval_sub_ms (&flow->flow_last, system_boot_time)); + } + return length; +} - *len_used = ret_len; - return (nflows); +static u_int +ipfix_flow_to_template_index (const struct FLOW *flow) +{ + u_int index = 0; + if (flow->af == AF_INET) + { + index = (flow->protocol == IPPROTO_ICMP) ? TMPLICMPV4 : TMPLV4; + } + else if (flow->af == AF_INET6) + { + index = (flow->protocol == IPPROTO_ICMPV6) ? TMPLICMPV6 : TMPLV6; + } + return index; } static int -ipfix_flow_to_bidirection_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, - struct FLOWTRACKPARAMETERS *param) -{ - union { - struct IPFIX_SOFTFLOWD_BIDIRECTION_DATA_V4 d4; - struct IPFIX_SOFTFLOWD_BIDIRECTION_DATA_V6 d6; - } d; - struct IPFIX_SOFTFLOWD_DATA_COMMON *dc; - struct IPFIX_SOFTFLOWD_DATA_BIDIRECTION *db; - union IPFIX_SOFTFLOWD_DATA_TIME *dt; - 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 IPFIX_SOFTFLOWD_BIDIRECTION_DATA_V4); - if (!(param->time_format == 'm' || param->time_format == 'M' || param->time_format == 'n')) { - freclen -= (sizeof(u_int64_t) - sizeof(u_int32_t)) * 2; - } - memcpy(&d.d4.sourceIPv4Address, &flow->addr[0].v4, 4); - memcpy(&d.d4.destinationIPv4Address, &flow->addr[1].v4, 4); - dc = &d.d4.c; - db = &d.d4.b; - dt = &d.d4.t; - dc->ipVersion = 4; - break; - case AF_INET6: - freclen = sizeof(struct IPFIX_SOFTFLOWD_BIDIRECTION_DATA_V6); - if (!(param->time_format == 'm' || param->time_format == 'M' || param->time_format == 'n')) { - freclen -= (sizeof(u_int64_t) - sizeof(u_int32_t)) * 2; - } - memcpy(&d.d6.sourceIPv6Address, &flow->addr[0].v6, 16); - memcpy(&d.d6.destinationIPv6Address, &flow->addr[1].v6, 16); - dc = &d.d6.c; - db = &d.d6.b; - dt = &d.d6.t; - dc->ipVersion = 6; - break; - default: - return (-1); - } - - if (param->time_format == 's') { - dt->u32.start = htonl(flow->flow_start.tv_sec); - dt->u32.end = htonl(flow->flow_last.tv_sec); - } -#if defined(htobe64) || defined(HAVE_DECL_HTOBE64) - else if (param->time_format == 'm') { /* milliseconds */ - dt->u64.start = - htobe64((u_int64_t)flow->flow_start.tv_sec * 1000 + (u_int64_t)flow->flow_start.tv_usec / 1000); - dt->u64.end = - htobe64((u_int64_t)flow->flow_last.tv_sec * 1000 + (u_int64_t)flow->flow_last.tv_usec / 1000); - } else if (param->time_format == 'M') { /* microseconds */ - dt->u64.start = - htobe64(((u_int64_t)flow->flow_start.tv_sec + JAN_1970) << 32 | (u_int32_t)(((u_int64_t)flow->flow_start.tv_usec << 32) / 1e6)); - dt->u64.end = - htobe64(((u_int64_t)flow->flow_last.tv_sec + JAN_1970) << 32 | (u_int32_t)(((u_int64_t)flow->flow_last.tv_usec << 32) / 1e6)); - } else if (param->time_format == 'n') { /* nanoseconds */ - dt->u64.start = - htobe64(((u_int64_t)flow->flow_start.tv_sec + JAN_1970) << 32 | (u_int32_t)(((u_int64_t)flow->flow_start.tv_usec << 32) / 1e9)); - dt->u64.end = - htobe64(((u_int64_t)flow->flow_last.tv_sec + JAN_1970) << 32 | (u_int32_t)(((u_int64_t)flow->flow_last.tv_usec << 32) / 1e9)); - } -#endif - else { - dt->u32.start = - htonl(timeval_sub_ms(&flow->flow_start, system_boot_time)); - dt->u32.end = - htonl(timeval_sub_ms(&flow->flow_last, system_boot_time)); - } - dc->octetDeltaCount = htonl(flow->octets[0]); - db->octetDeltaCount = htonl(flow->octets[1]); - dc->packetDeltaCount = htonl(flow->packets[0]); - db->packetDeltaCount = htonl(flow->packets[1]); - dc->ingressInterface = dc->egressInterface = htonl(ifidx); - dc->sourceTransportPort = flow->port[0]; - dc->destinationTransportPort = flow->port[1]; - dc->protocolIdentifier = flow->protocol; - dc->tcpControlBits = flow->tcp_flags[0]; - db->tcpControlBits = flow->tcp_flags[1]; - dc->ipClassOfService = flow->tos[0]; - db->ipClassOfService = flow->tos[1]; - if (flow->protocol == IPPROTO_ICMP || flow->protocol == IPPROTO_ICMPV6) { - dc->icmpTypeCode = flow->port[1]; - db->icmpTypeCode = flow->port[0]; - } - dc->vlanId = htons(flow->vlanid); - - if (flow->octets[0] > 0 || flow->octets[1] > 0) { - if (ret_len + freclen > len) - return (-1); - memcpy(packet + ret_len, &d, freclen); - ret_len += freclen; - nflows++; - } +ipfix_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, + struct FLOWTRACKPARAMETERS *param, u_int8_t bi_flag) +{ + struct IPFIX_SOFTFLOWD_DATA_V4ADDR *d4[2] = { NULL, NULL }; + struct IPFIX_SOFTFLOWD_DATA_V6ADDR *d6[2] = { NULL, NULL }; + union IPFIX_SOFTFLOWD_DATA_TIME *dt[2] = { NULL, NULL }; + struct IPFIX_SOFTFLOWD_DATA_COMMON *dc[2] = { NULL, NULL }; + struct IPFIX_SOFTFLOWD_DATA_TRANSPORT *dtr[2] = { NULL, NULL }; + struct IPFIX_SOFTFLOWD_DATA_ICMP *di[2] = { NULL, NULL }; + struct IPFIX_SOFTFLOWD_DATA_VLAN *dv[2] = { NULL, NULL }; + struct IPFIX_SOFTFLOWD_DATA_ETHER *de[2] = { NULL, NULL }; + struct IPFIX_SOFTFLOWD_DATA_BICOMMON *dbc = NULL; + struct IPFIX_SOFTFLOWD_DATA_BITRANSPORT *dbtr = NULL; + struct IPFIX_SOFTFLOWD_DATA_BIICMP *dbi = NULL; + + u_int freclen = 0, nflows = 0, offset = 0; + u_int frecnum = bi_flag ? 1 : 2; + u_int tmplindex = ipfix_flow_to_template_index (flow); + freclen = template[tmplindex].data_len; + if (len < freclen * frecnum) + return (-1); + + for (int i = 0; i < frecnum; i++) + { + if (bi_flag == 0 && flow->octets[i] == 0) + continue; + nflows++; + if (flow->af == AF_INET) + { + d4[i] = + (struct IPFIX_SOFTFLOWD_DATA_V4ADDR *) &packet[offset]; + memcpy (&d4[i]->sourceIPv4Address, &flow->addr[i].v4, 4); + memcpy (&d4[i]->destinationIPv4Address, + &flow->addr[i ^ 1].v4, 4); + offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_V4ADDR); + } + else if (flow->af == AF_INET6) + { + d6[i] = + (struct IPFIX_SOFTFLOWD_DATA_V6ADDR *) &packet[offset]; + memcpy (&d6[i]->sourceIPv6Address, &flow->addr[i].v6, 16); + memcpy (&d6[i]->destinationIPv6Address, + &flow->addr[i ^ 1].v6, 16); + offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_V6ADDR); + } + + dt[i] = (union IPFIX_SOFTFLOWD_DATA_TIME *) &packet[offset]; + offset += copy_data_time (dt[i], flow, system_boot_time, param); + + dc[i] = (struct IPFIX_SOFTFLOWD_DATA_COMMON *) &packet[offset]; + dc[i]->octetDeltaCount = htonl (flow->octets[i]); + dc[i]->packetDeltaCount = htonl (flow->packets[i]); + dc[i]->ingressInterface = dc[i]->egressInterface = htonl (ifidx); + offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_COMMON); + + if (flow->protocol != IPPROTO_ICMP + && flow->protocol != IPPROTO_ICMPV6) + { + dtr[i] = + (struct IPFIX_SOFTFLOWD_DATA_TRANSPORT *) &packet[offset]; + dtr[i]->sourceTransportPort = flow->port[i]; + dtr[i]->destinationTransportPort = flow->port[i ^ 1]; + dtr[i]->protocolIdentifier = flow->protocol; + dtr[i]->tcpControlBits = flow->tcp_flags[i]; + dtr[i]->ipClassOfService = flow->tos[i]; + dtr[i]->ipVersion = (flow->af == AF_INET) ? 4 : 6; + offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_TRANSPORT); + } + else + { + di[i] = (struct IPFIX_SOFTFLOWD_DATA_ICMP *) &packet[offset]; + di[i]->icmpTypeCode = flow->port[i ^ 1]; + di[i]->ipClassOfService = flow->tos[i]; + di[i]->ipVersion = (flow->af == AF_INET) ? 4 : 6; + offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_ICMP); + } + if (param->track_level >= TRACK_FULL_VLAN) + { + dv[i] = (struct IPFIX_SOFTFLOWD_DATA_VLAN *) &packet[offset]; + dv[i]->vlanId = flow->vlanid[i]; + dv[i]->postVlanId = flow->vlanid[i ^ 1]; + offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_VLAN); + } + if (param->track_level >= TRACK_FULL_VLAN_ETHER) + { + de[i] = (struct IPFIX_SOFTFLOWD_DATA_ETHER *) &packet[offset]; + memcpy (&de[i]->sourceMacAddress, &flow->ethermac[i], 6); + memcpy (&de[i]->destinationMacAddress, + &flow->ethermac[i ^ 1], 6); + offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_ETHER); + } + if (bi_flag && i == 0) + { + dbc = + (struct IPFIX_SOFTFLOWD_DATA_BICOMMON *) &packet[offset]; + dbc->octetDeltaCount = htonl (flow->octets[1]); + dbc->packetDeltaCount = htonl (flow->packets[1]); + dbc->ipClassOfService = flow->tos[1]; + offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_BICOMMON); + if (flow->protocol != IPPROTO_ICMP + && flow->protocol != IPPROTO_ICMPV6) + { + dbtr = + (struct IPFIX_SOFTFLOWD_DATA_BITRANSPORT *) + &packet[offset]; + dbtr->tcpControlBits = flow->tcp_flags[1]; + offset += + sizeof (struct IPFIX_SOFTFLOWD_DATA_BITRANSPORT); + } + else + { + dbi = + (struct IPFIX_SOFTFLOWD_DATA_BIICMP *) + &packet[offset]; + dbi->icmpTypeCode = flow->port[1]; + offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_BIICMP); + } + } + } + *len_used = offset; + return (nflows); +} - *len_used = ret_len; - return (nflows); +static int +valuate_icmp (struct FLOW *flow) +{ + if (flow == NULL) + return -1; + if (flow->af == AF_INET) + if (flow->protocol == IPPROTO_ICMP) + return 1; + else + return 0; + else if (flow->af == AF_INET6) + if (flow->protocol == IPPROTO_ICMPV6) + return 1; + else + return 0; + return -1; } +void +ipfix_resend_template (void) +{ + if (ipfix_pkts_until_template > 0) + ipfix_pkts_until_template = 0; +} + +void +memcpy_template (u_char * packet, u_int * offset, + struct IPFIX_SOFTFLOWD_TEMPLATE *template, u_int8_t bi_flag) +{ + int size = ntohs (template->h.c.length) - + template->bi_count * sizeof (struct IPFIX_VENDOR_FIELD_SPECIFIER); + memcpy (packet + *offset, template, size); + *offset += size; + if (bi_flag) + { + size = + template->bi_count * + sizeof (struct IPFIX_VENDOR_FIELD_SPECIFIER); + memcpy (packet + *offset, template->v, size); + *offset += size; + } +} /* - * Given an array of expired flows, send netflow v9 report packets + * Given an array of expired flows, send ipfix report packets * Returns number of packets sent or -1 on error */ -int -send_ipfix(struct FLOW **flows, int num_flows, int nfsock, - u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param, - int verbose_flag) -{ - struct IPFIX_HEADER *ipfix; - struct IPFIX_SET_HEADER *dh; - struct timeval now; - u_int offset, last_af, i, j, num_packets, inc, last_valid; - socklen_t errsz; - int err, r; - u_int records; - u_char packet[IPFIX_SOFTFLOWD_MAX_PACKET_SIZE]; - struct timeval *system_boot_time = ¶m->system_boot_time; - u_int64_t *flows_exported = ¶m->flows_exported; - u_int64_t *records_sent = ¶m->records_sent; - struct OPTION *option = ¶m->option; - - gettimeofday(&now, NULL); - - if (ipfix_pkts_until_template == -1) { - ipfix_init_template(param); - ipfix_pkts_until_template = 0; - if (option != NULL){ - ipfix_init_option(system_boot_time, option); - } - } - - last_valid = num_packets = 0; - for (j = 0; j < num_flows;) { - bzero(packet, sizeof(packet)); - ipfix = (struct IPFIX_HEADER *)packet; - - ipfix->version = htons(10); - ipfix->length = 0; /* Filled as we go, htons at end */ - ipfix->export_time = htonl(time(NULL)); - ipfix->od_id = 0; - offset = sizeof(*ipfix); - - /* Refresh template headers if we need to */ - if (ipfix_pkts_until_template <= 0) { - memcpy(packet + offset, &v4_template, - sizeof(v4_template)); - offset += sizeof(v4_template); - memcpy(packet + offset, &v6_template, - sizeof(v6_template)); - offset += sizeof(v6_template); - if (option != NULL){ - memcpy(packet + offset, &option_template, - sizeof(option_template)); - offset += sizeof(option_template); - memcpy(packet + offset, &option_data, - sizeof(option_data)); - offset += sizeof(option_data); - } - - ipfix_pkts_until_template = IPFIX_DEFAULT_TEMPLATE_INTERVAL; - } - - dh = NULL; - last_af = 0; - records = 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->length += 4 - (offset % 4); - offset += 4 - (offset % 4); - } - /* Finalise last header */ - dh->length = htons(dh->length); - } - if (offset + sizeof(*dh) > sizeof(packet)) { - /* Mark header is finished */ - dh = NULL; - break; - } - dh = (struct IPFIX_SET_HEADER *) - (packet + offset); - dh->set_id = - (flows[i + j]->af == AF_INET) ? - v4_template.h.r.template_id : - v6_template.h.r.template_id; - last_af = flows[i + j]->af; - last_valid = offset; - dh->length = sizeof(*dh); /* Filled as we go */ - offset += sizeof(*dh); - } - - r = ipfix_flow_to_flowset(flows[i + j], packet + offset, - sizeof(packet) - offset, ifidx, system_boot_time, &inc, param); - if (r <= 0) { - /* yank off data header, if we had to go back */ - if (last_valid) - offset = last_valid; - break; - } - records += (u_int)r; - offset += inc; - dh->length += inc; - last_valid = 0; /* Don't clobber this header now */ - if (verbose_flag) { - logit(LOG_DEBUG, "Flow %d/%d: " - "r %d offset %d ie %04x len %d(0x%04x)", - r, i, j, offset, - dh->set_id, dh->length, - dh->length); - } - } - /* Don't finish header if it has already been done */ - if (dh != NULL) { - if (offset % 4 != 0) { - /* Pad to multiple of 4 */ - dh->length += 4 - (offset % 4); - offset += 4 - (offset % 4); - } - /* Finalise last header */ - dh->length = htons(dh->length); - } - ipfix->length = htons(offset); - *records_sent += records; - ipfix->sequence = htonl((u_int32_t)(*records_sent & 0x00000000ffffffff)); - - if (verbose_flag) - logit(LOG_DEBUG, "Sending flow packet len = %d", offset); - errsz = sizeof(err); - /* Clear ICMP errors */ - getsockopt(nfsock, SOL_SOCKET, SO_ERROR, &err, &errsz); - if (send(nfsock, packet, (size_t)offset, 0) == -1) - return (-1); - num_packets++; - ipfix_pkts_until_template--; +static int +send_ipfix_common (struct FLOW **flows, int num_flows, + int nfsock, u_int16_t ifidx, + struct FLOWTRACKPARAMETERS *param, + int verbose_flag, u_int8_t bi_flag, u_int16_t version) +{ + struct IPFIX_HEADER *ipfix; + struct NFLOW9_HEADER *nf9; + struct IPFIX_SET_HEADER *dh; + struct timeval now; + u_int offset, last_af, i, j, num_packets, inc, last_valid; + int8_t icmp_flag, last_icmp_flag; + socklen_t errsz; + int err, r; + u_int records; + u_char packet[IPFIX_SOFTFLOWD_MAX_PACKET_SIZE]; + struct timeval *system_boot_time = ¶m->system_boot_time; + u_int64_t *flows_exported = ¶m->flows_exported; + u_int64_t *records_sent = ¶m->records_sent; + struct OPTION *option = ¶m->option; + u_int tmplindex = 0; + + gettimeofday (&now, NULL); + + if (ipfix_pkts_until_template == -1) + { + ipfix_init_template (param, bi_flag, version); + ipfix_pkts_until_template = 0; + if (option != NULL) + { + if (version == 10) + { + ipfix_init_option (system_boot_time, option); + } + else + { + nflow9_init_option (ifidx, option); + } + } + } + + last_valid = num_packets = 0; + for (j = 0; j < num_flows;) + { + bzero (packet, sizeof (packet)); + if (version == 10) + { + ipfix = (struct IPFIX_HEADER *) packet; + ipfix->version = htons (version); + ipfix->length = 0; /* Filled as we go, htons at end */ + ipfix->export_time = htonl (time (NULL)); + ipfix->od_id = 0; + offset = sizeof (*ipfix); + } + else if (version == 9) + { + nf9 = (struct NFLOW9_HEADER *) packet; + nf9->version = htons (version); + 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 (ipfix_pkts_until_template <= 0) + { + for (int i = 0; i < TMPLMAX; i++) + { + memcpy_template (packet, &offset, + &template[i], bi_flag); + } + if (option != NULL) + { + u_int16_t opt_tmpl_len = + ntohs (option_template.h.c.length); + memcpy (packet + offset, &option_template, + opt_tmpl_len); + offset += opt_tmpl_len; + if (version == 10) + { + memcpy (packet + offset, &option_data, + sizeof (option_data)); + offset += sizeof (option_data); + } + else if (version == 9) + { + memcpy (packet + offset, &nf9opt_data, + sizeof (nf9opt_data)); + offset += sizeof (nf9opt_data); + } + } + + ipfix_pkts_until_template = IPFIX_DEFAULT_TEMPLATE_INTERVAL; + } + + dh = NULL; + last_af = 0; + last_icmp_flag = -1; + records = 0; + for (i = 0; i + j < num_flows; i++) + { + icmp_flag = valuate_icmp (flows[i + j]); + if (dh == NULL || flows[i + j]->af != last_af || + icmp_flag != last_icmp_flag) + { + if (dh != NULL) + { + if (offset % 4 != 0) + { + /* Pad to multiple of 4 */ + dh->length += 4 - (offset % 4); + offset += 4 - (offset % 4); + } + /* Finalise last header */ + dh->length = htons (dh->length); + } + if (offset + sizeof (*dh) > sizeof (packet)) + { + /* Mark header is finished */ + dh = NULL; + break; + } + dh = (struct IPFIX_SET_HEADER *) (packet + offset); + tmplindex = ipfix_flow_to_template_index (flows[i + j]); + dh->set_id = template[tmplindex].h.r.template_id; + last_af = flows[i + j]->af; + last_icmp_flag = icmp_flag; + last_valid = offset; + dh->length = sizeof (*dh); /* Filled as we go */ + offset += sizeof (*dh); + } + r = ipfix_flow_to_flowset (flows[i + j], + packet + offset, + sizeof (packet) - offset, + ifidx, system_boot_time, + &inc, param, bi_flag); + if (r <= 0) + { + /* yank off data header, if we had to go back */ + if (last_valid) + offset = last_valid; + break; + } + records += (u_int) r; + offset += inc; + dh->length += inc; + last_valid = 0; /* Don't clobber this header now */ + if (verbose_flag) + { + logit (LOG_DEBUG, "Flow %d/%d: " + "r %d offset %d ie %04x len %d(0x%04x)", + r, i, j, offset, + dh->set_id, dh->length, dh->length); + } + } + /* Don't finish header if it has already been done */ + if (dh != NULL) + { + if (offset % 4 != 0) + { + /* Pad to multiple of 4 */ + dh->length += 4 - (offset % 4); + offset += 4 - (offset % 4); + } + /* Finalise last header */ + dh->length = htons (dh->length); + } + ipfix->length = htons (offset); + *records_sent += records; + ipfix->sequence = + htonl ((u_int32_t) (*records_sent & 0x00000000ffffffff)); + + if (verbose_flag) + logit (LOG_DEBUG, "Sending flow packet len = %d", offset); + errsz = sizeof (err); + /* Clear ICMP errors */ + getsockopt (nfsock, SOL_SOCKET, SO_ERROR, &err, &errsz); + if (send (nfsock, packet, (size_t) offset, 0) == -1) + return (-1); + num_packets++; + ipfix_pkts_until_template--; - j += i; - } + j += i; + } - *flows_exported += j; - return (num_packets); + *flows_exported += j; + return (num_packets); } -void -ipfix_resend_template(void) +int +send_nflow9 (struct FLOW **flows, int num_flows, int nfsock, + u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param, + int verbose_flag) { - if (ipfix_pkts_until_template > 0) - ipfix_pkts_until_template = 0; + return send_ipfix_common (flows, num_flows, nfsock, ifidx, + param, verbose_flag, 0, 9); } -/* - * Given an array of expired flows, send netflow v9 report packets - * Returns number of packets sent or -1 on error - */ int -send_ipfix_bidirection(struct FLOW **flows, int num_flows, int nfsock, - u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param, - int verbose_flag) -{ - struct IPFIX_HEADER *ipfix; - struct IPFIX_SET_HEADER *dh; - struct timeval now; - u_int offset, last_af, i, j, num_packets, inc, last_valid; - socklen_t errsz; - int err, r; - u_int records; - u_char packet[IPFIX_SOFTFLOWD_MAX_PACKET_SIZE]; - struct timeval *system_boot_time = ¶m->system_boot_time; - u_int64_t *flows_exported = ¶m->flows_exported; - u_int64_t *records_sent = ¶m->records_sent; - struct OPTION *option = ¶m->option; - - gettimeofday(&now, NULL); - - if (ipfix_pkts_until_template == -1) { - ipfix_init_template_bidirection(param); - ipfix_pkts_until_template = 0; - if (option != NULL){ - ipfix_init_option(system_boot_time, option); - } - } - - last_valid = num_packets = 0; - for (j = 0; j < num_flows;) { - bzero(packet, sizeof(packet)); - ipfix = (struct IPFIX_HEADER *)packet; - - ipfix->version = htons(10); - ipfix->length = 0; /* Filled as we go, htons at end */ - ipfix->export_time = htonl(time(NULL)); - ipfix->od_id = 0; - offset = sizeof(*ipfix); - - /* Refresh template headers if we need to */ - if (ipfix_pkts_until_template <= 0) { - memcpy(packet + offset, &v4_bidirection_template, - sizeof(v4_bidirection_template)); - offset += sizeof(v4_bidirection_template); - memcpy(packet + offset, &v6_bidirection_template, - sizeof(v6_bidirection_template)); - offset += sizeof(v6_bidirection_template); - if (option != NULL){ - memcpy(packet + offset, &option_template, - sizeof(option_template)); - offset += sizeof(option_template); - memcpy(packet + offset, &option_data, - sizeof(option_data)); - offset += sizeof(option_data); - } - - ipfix_pkts_until_template = IPFIX_DEFAULT_TEMPLATE_INTERVAL; - } - - dh = NULL; - last_af = 0; - records = 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->length += 4 - (offset % 4); - offset += 4 - (offset % 4); - } - /* Finalise last header */ - dh->length = htons(dh->length); - } - if (offset + sizeof(*dh) > sizeof(packet)) { - /* Mark header is finished */ - dh = NULL; - break; - } - dh = (struct IPFIX_SET_HEADER *) - (packet + offset); - dh->set_id = - (flows[i + j]->af == AF_INET) ? - v4_bidirection_template.h.r.template_id : - v6_bidirection_template.h.r.template_id; - last_af = flows[i + j]->af; - last_valid = offset; - dh->length = sizeof(*dh); /* Filled as we go */ - offset += sizeof(*dh); - } - - r = ipfix_flow_to_bidirection_flowset(flows[i + j], - packet + offset, - sizeof(packet) - offset, - ifidx, - system_boot_time, - &inc, param); - if (r <= 0) { - /* yank off data header, if we had to go back */ - if (last_valid) - offset = last_valid; - break; - } - records += (u_int)r; - offset += inc; - dh->length += inc; - last_valid = 0; /* Don't clobber this header now */ - if (verbose_flag) { - logit(LOG_DEBUG, "Flow %d/%d: " - "r %d offset %d ie %04x len %d(0x%04x)", - r, i, j, offset, - dh->set_id, dh->length, - dh->length); - } - } - /* Don't finish header if it has already been done */ - if (dh != NULL) { - if (offset % 4 != 0) { - /* Pad to multiple of 4 */ - dh->length += 4 - (offset % 4); - offset += 4 - (offset % 4); - } - /* Finalise last header */ - dh->length = htons(dh->length); - } - ipfix->length = htons(offset); - *records_sent += records; - ipfix->sequence = htonl((u_int32_t)(*records_sent & 0x00000000ffffffff)); - - if (verbose_flag) - logit(LOG_DEBUG, "Sending flow packet len = %d", offset); - errsz = sizeof(err); - /* Clear ICMP errors */ - getsockopt(nfsock, SOL_SOCKET, SO_ERROR, &err, &errsz); - if (send(nfsock, packet, (size_t)offset, 0) == -1) - return (-1); - num_packets++; - ipfix_pkts_until_template--; - - j += i; - } +send_ipfix (struct FLOW **flows, int num_flows, int nfsock, + u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param, + int verbose_flag) +{ + return send_ipfix_common (flows, num_flows, nfsock, ifidx, + param, verbose_flag, 0, 10); +} - *flows_exported += j; - return (num_packets); +int +send_ipfix_bi (struct FLOW **flows, int num_flows, int nfsock, + u_int16_t ifidx, + struct FLOWTRACKPARAMETERS *param, int verbose_flag) +{ + return send_ipfix_common (flows, num_flows, nfsock, ifidx, + param, verbose_flag, 1, 10); } --- a/softflowd.c +++ b/softflowd.c @@ -110,8 +110,9 @@ static const struct NETFLOW_SENDER nf[] = { { 5, send_netflow_v5, NULL, 0 }, { 1, send_netflow_v1, NULL, 0 }, - { 9, send_netflow_v9, NULL, 1 }, - { 10, send_ipfix, send_ipfix_bidirection, 1 }, + //{ 9, send_netflow_v9, NULL, 1 }, + { 9, send_nflow9, NULL, 1 }, + { 10, send_ipfix, send_ipfix_bi, 1 }, { -1, NULL, NULL, 0 }, }; @@ -147,6 +148,12 @@ if (a->vlanid != b->vlanid) return (a->vlanid > b->vlanid ? 1 : -1); + if ((r = memcmp(&a->ethermac[0], &b->ethermac[0], 6)) != 0) + return (r > 0 ? 1 : -1); + + if ((r = memcmp(&a->ethermac[1], &b->ethermac[1], 6)) != 0) + return (r > 0 ? 1 : -1); + if (a->af != b->af) return (a->af > b->af ? 1 : -1); @@ -356,29 +363,34 @@ return (0); } -/* Convert a IPv4 packet to a partial flow record (used for comparison) */ static int -ipv4_to_flowrec(struct FLOW *flow, const u_int8_t *pkt, size_t caplen, - size_t len, int *isfrag, int af, u_int16_t vlanid) -{ - const struct ip *ip = (const struct ip *)pkt; - int ndx; - +make_ndx_ipv4(const struct ip *ip, size_t caplen) { if (caplen < 20 || caplen < ip->ip_hl * 4) return (-1); /* Runt packet */ if (ip->ip_v != 4) return (-1); /* Unsupported IP version */ - + /* Prepare to store flow in canonical format */ - ndx = memcmp(&ip->ip_src, &ip->ip_dst, sizeof(ip->ip_src)) > 0 ? 1 : 0; - + return(memcmp(&ip->ip_src, &ip->ip_dst, sizeof(ip->ip_src)) > 0 ? 1 : 0); +} + +/* Convert a IPv4 packet to a partial flow record (used for comparison) */ +static int +ipv4_to_flowrec(struct FLOW *flow, const u_int8_t *pkt, size_t caplen, + size_t len, int *isfrag, int af, int ndx) +{ + const struct ip *ip = (const struct ip *)pkt; + //int ndx = make_ndx_ipv4 (ip, caplen); + if (ndx < 0) + return (-1); + flow->af = af; flow->addr[ndx].v4 = ip->ip_src; flow->addr[ndx ^ 1].v4 = ip->ip_dst; flow->protocol = ip->ip_p; flow->octets[ndx] = len; flow->packets[ndx] = 1; - flow->vlanid = vlanid; + flow->tos[ndx] = ip->ip_tos; *isfrag = (ntohs(ip->ip_off) & (IP_OFFMASK|IP_MF)) ? 1 : 0; @@ -390,16 +402,8 @@ caplen - (ip->ip_hl * 4), *isfrag, ip->ip_p, ndx)); } -/* Convert a IPv6 packet to a partial flow record (used for comparison) */ static int -ipv6_to_flowrec(struct FLOW *flow, const u_int8_t *pkt, size_t caplen, - size_t len, int *isfrag, int af, u_int16_t vlanid) -{ - const struct ip6_hdr *ip6 = (const struct ip6_hdr *)pkt; - const struct ip6_ext *eh6; - const struct ip6_frag *fh6; - int ndx, nxt; - +make_ndx_ipv6(const struct ip6_hdr *ip6, size_t caplen) { if (caplen < sizeof(*ip6)) return (-1); /* Runt packet */ @@ -407,16 +411,30 @@ return (-1); /* Unsupported IPv6 version */ /* Prepare to store flow in canonical format */ - ndx = memcmp(&ip6->ip6_src, &ip6->ip6_dst, - sizeof(ip6->ip6_src)) > 0 ? 1 : 0; - + return(memcmp(&ip6->ip6_src, &ip6->ip6_dst, + sizeof(ip6->ip6_src)) > 0 ? 1 : 0); +} + +/* Convert a IPv6 packet to a partial flow record (used for comparison) */ +static int +ipv6_to_flowrec(struct FLOW *flow, const u_int8_t *pkt, size_t caplen, + size_t len, int *isfrag, int af, int ndx) +{ + const struct ip6_hdr *ip6 = (const struct ip6_hdr *)pkt; + const struct ip6_ext *eh6; + const struct ip6_frag *fh6; + int nxt; + + if (ndx < 0) + return (-1); + flow->af = af; flow->ip6_flowlabel[ndx] = ip6->ip6_flow & IPV6_FLOWLABEL_MASK; flow->addr[ndx].v6 = ip6->ip6_src; flow->addr[ndx ^ 1].v6 = ip6->ip6_dst; flow->octets[ndx] = len; flow->packets[ndx] = 1; - flow->vlanid = vlanid; + flow->tos[ndx] = (ntohl(ip6->ip6_flow) & ntohl(0x0ff00000)) >> 20; *isfrag = 0; nxt = ip6->ip6_nxt; @@ -457,6 +475,27 @@ return (transport_to_flowrec(flow, pkt, caplen, *isfrag, nxt, ndx)); } +static int +vlan_to_flowrec(struct FLOW *flow, u_int16_t vlanid, int ndx) +{ + if (ndx < 0) + return (-1); + return (flow->vlanid[ndx] = vlanid); + +} + +static int +ether_to_flowrec(struct FLOW *flow, struct ether_header *ether, int ndx) +{ + if (ndx < 0) + return (-1); + if (ether == NULL) + return (-1); + memcpy(flow->ethermac[ndx], ether->ether_shost, ETH_ALEN); + memcpy(flow->ethermac[ndx^1], ether->ether_dhost, ETH_ALEN); + return (1); +} + static void flow_update_expiry(struct FLOWTRACK *ft, struct FLOW *flow) { @@ -555,11 +594,11 @@ */ static int process_packet(struct FLOWTRACK *ft, const u_int8_t *pkt, int af, - const u_int32_t caplen, const u_int32_t len, u_int16_t vlanid, - const struct timeval *received_time) + const u_int32_t caplen, const u_int32_t len, struct ether_header *ether, + u_int16_t vlanid, const struct timeval *received_time) { struct FLOW tmp, *flow; - int frag; + int frag, ndx; ft->param.total_packets++; @@ -567,11 +606,13 @@ memset(&tmp, 0, sizeof(tmp)); switch (af) { case AF_INET: - if (ipv4_to_flowrec(&tmp, pkt, caplen, len, &frag, af, vlanid) == -1) + ndx = make_ndx_ipv4((const struct ip *)pkt, caplen); + if (ipv4_to_flowrec(&tmp, pkt, caplen, len, &frag, af, ndx) == -1) goto bad; break; case AF_INET6: - if (ipv6_to_flowrec(&tmp, pkt, caplen, len, &frag, af, vlanid) == -1) + ndx = make_ndx_ipv6((const struct ip6_hdr *)pkt, caplen); + if (ipv6_to_flowrec(&tmp, pkt, caplen, len, &frag, af, ndx) == -1) goto bad; break; default: @@ -593,8 +634,11 @@ tmp.tcp_flags[0] = tmp.tcp_flags[1] = 0; /* FALLTHROUGH */ case TRACK_FULL: - tmp.vlanid = 0; + //tmp.vlanid = 0; case TRACK_FULL_VLAN: + vlan_to_flowrec(&tmp, vlanid, ndx); + case TRACK_FULL_VLAN_ETHER: + ether_to_flowrec(&tmp, ether, ndx); break; } @@ -1092,7 +1136,7 @@ * packet should be skipped */ static int -datalink_check(int linktype, const u_int8_t *pkt, u_int32_t caplen, int *af, u_int16_t *vlanid) +datalink_check(int linktype, const u_int8_t *pkt, u_int32_t caplen, int *af, struct ether_header **ether, u_int16_t *vlanid) { int i, j; u_int32_t frametype; @@ -1116,12 +1160,14 @@ /* Processing 802.1Q vlan in ethernet */ if (linktype == DLT_EN10MB) { + if (ether != NULL) + *ether = (struct ether_header *)pkt; for (j = 0; j < dl->ft_len; j++) { frametype <<= 8; frametype |= pkt[j + dl->ft_off]; } frametype &= dl->ft_mask; - if (frametype == 0x8100) { + if (frametype == ETHERTYPE_VLAN) { for (j = 0; j < 2; j++) { *vlanid <<= 8; *vlanid |= pkt[j + dl->skiplen]; @@ -1166,6 +1212,7 @@ struct CB_CTXT *cb_ctxt = (struct CB_CTXT *)user_data; struct timeval tv; u_int16_t vlanid = 0; + struct ether_header *ether = NULL; if (cb_ctxt->ft->param.option.sample && (cb_ctxt->ft->param.total_packets + @@ -1174,14 +1221,14 @@ cb_ctxt->ft->param.non_sampled_packets++; return; } - s = datalink_check(cb_ctxt->linktype, pkt, phdr->caplen, &af, &vlanid); + s = datalink_check(cb_ctxt->linktype, pkt, phdr->caplen, &af, ðer, &vlanid); if (s < 0 || (!cb_ctxt->want_v6 && af == AF_INET6)) { cb_ctxt->ft->param.non_ip_packets++; } else { tv.tv_sec = phdr->ts.tv_sec; tv.tv_usec = phdr->ts.tv_usec; if (process_packet(cb_ctxt->ft, pkt + s, af, phdr->caplen - s, - phdr->len - s, vlanid, &tv) == PP_MALLOC_FAIL) + phdr->len - s, ether, vlanid, &tv) == PP_MALLOC_FAIL) cb_ctxt->fatal = 1; } } @@ -1433,7 +1480,7 @@ bpf_net = bpf_mask = 0; } *linktype = pcap_datalink(*pcap); - if (datalink_check(*linktype, NULL, 0, NULL, NULL) == -1) { + if (datalink_check(*linktype, NULL, 0, NULL, NULL, NULL) == -1) { fprintf(stderr, "Unsupported datalink type %d\n", *linktype); exit(1); } @@ -1819,6 +1866,9 @@ flowtrack.param.track_level = TRACK_IP_ONLY; else if (strcasecmp(optarg, "vlan") == 0) flowtrack.param.track_level = TRACK_FULL_VLAN; + else if (strcasecmp(optarg, "ether") == 0) + flowtrack.param.track_level = TRACK_FULL_VLAN_ETHER; + else { fprintf(stderr, "Unknown flow tracking " "level\n"); @@ -1953,7 +2003,12 @@ if ((pidfile = fopen(pidfile_path, "r")) != NULL) { int pid; - fscanf(pidfile,"%u", &pid); + if (fscanf(pidfile,"%u", &pid) == EOF) { + //fscanf error + if (ferror(pidfile)){ + perror("fscanf"); + } + } fclose(pidfile); /* Check if the pid exists */ --- a/softflowd.h +++ b/softflowd.h @@ -74,6 +74,7 @@ #define TRACK_IP_PROTO 3 /* src/dst/proto 3-tuple */ #define TRACK_IP_ONLY 4 /* src/dst tuple */ #define TRACK_FULL_VLAN 5 /* src/dst/addr/port/proto/tos/vlanid 7-tuple */ +#define TRACK_FULL_VLAN_ETHER 6 /* src/dst/addr/port/proto/tos/vlanid/src-mac/dst-mac 9-tuple */ /* * This structure contains optional information carried by Option Data @@ -190,7 +191,8 @@ u_int16_t port[2]; /* Endpoint ports */ u_int8_t tcp_flags[2]; /* Cumulative OR of flags */ u_int8_t tos[2]; /* Tos */ - u_int16_t vlanid; /* vlanid */ + u_int16_t vlanid[2]; /* vlanid */ + uint8_t ethermac[2][6]; u_int8_t protocol; /* Protocol */ }; @@ -232,13 +234,16 @@ int send_netflow_v9(struct FLOW **flows, int num_flows, int nfsock, u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param, int verbose_flag); +int send_nflow9(struct FLOW **flows, int num_flows, int nfsock, + u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param, + int verbose_flag); int send_ipfix(struct FLOW **flows, int num_flows, int nfsock, - u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param, - int verbose_flag); -int send_ipfix_bidirection(struct FLOW **flows, int num_flows, int nfsock, - u_int16_t ifidx, - struct FLOWTRACKPARAMETERS *param, + u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param, int verbose_flag); +int send_ipfix_bi(struct FLOW **flows, int num_flows, int nfsock, + u_int16_t ifidx, + struct FLOWTRACKPARAMETERS *param, + int verbose_flag); /* Force a resend of the flow template */ void netflow9_resend_template(void);