/* * netflow.c * * Copyright (C) 2011-22 - ntop.org * * nDPI is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * nDPI is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with nDPI. If not, see . * */ #include "ndpi_protocol_ids.h" #define NDPI_CURRENT_PROTO NDPI_PROTOCOL_NETFLOW #include "ndpi_api.h" #include "ndpi_private.h" #ifdef WIN32 extern int gettimeofday(struct timeval * tp, struct timezone * tzp); #endif #define do_gettimeofday(a) gettimeofday(a, NULL) struct flow_ver1_rec { u_int32_t srcaddr; /* Source IP Address */ u_int32_t dstaddr; /* Destination IP Address */ u_int32_t nexthop; /* Next hop router's IP Address */ u_int16_t input; /* Input interface index */ u_int16_t output; /* Output interface index */ u_int32_t dPkts; /* Packets sent in Duration */ u_int32_t dOctets; /* Octets sent in Duration */ u_int32_t first; /* SysUptime at start of flow */ u_int32_t last; /* and of last packet of the flow */ u_int16_t srcport; /* TCP/UDP source port number (.e.g, FTP, Telnet, etc.,or equivalent) */ u_int16_t dstport; /* TCP/UDP destination port number (.e.g, FTP, Telnet, etc.,or equivalent) */ u_int16_t pad; /* pad to word boundary */ u_int8_t proto; /* IP protocol, e.g., 6=TCP, 17=UDP, etc... */ u_int8_t tos; /* IP Type-of-Service */ u_int8_t pad2[7]; /* pad to word boundary */ }; struct flow_ver5_rec { u_int32_t srcaddr; /* Source IP Address */ u_int32_t dstaddr; /* Destination IP Address */ u_int32_t nexthop; /* Next hop router's IP Address */ u_int16_t input; /* Input interface index */ u_int16_t output; /* Output interface index */ u_int32_t dPkts; /* Packets sent in Duration (milliseconds between 1st & last packet in this flow)*/ u_int32_t dOctets; /* Octets sent in Duration (milliseconds between 1st & last packet in this flow)*/ u_int32_t first; /* SysUptime at start of flow */ u_int32_t last; /* and of last packet of the flow */ u_int16_t srcport; /* TCP/UDP source port number (.e.g, FTP, Telnet, etc.,or equivalent) */ u_int16_t dstport; /* TCP/UDP destination port number (.e.g, FTP, Telnet, etc.,or equivalent) */ u_int8_t pad1; /* pad to word boundary */ u_int8_t tcp_flags; /* Cumulative OR of tcp flags */ u_int8_t proto; /* IP protocol, e.g., 6=TCP, 17=UDP, etc... */ u_int8_t tos; /* IP Type-of-Service */ u_int16_t src_as; /* source peer/origin Autonomous System */ u_int16_t dst_as; /* dst peer/origin Autonomous System */ u_int8_t src_mask; /* source route's mask bits */ u_int8_t dst_mask; /* destination route's mask bits */ u_int16_t pad2; /* pad to word boundary */ }; struct flow_ver7_rec { u_int32_t srcaddr; /* Source IP Address */ u_int32_t dstaddr; /* Destination IP Address */ u_int32_t nexthop; /* Next hop router's IP Address */ u_int16_t input; /* Input interface index */ u_int16_t output; /* Output interface index */ u_int32_t dPkts; /* Packets sent in Duration */ u_int32_t dOctets; /* Octets sent in Duration */ u_int32_t first; /* SysUptime at start of flow */ u_int32_t last; /* and of last packet of the flow */ u_int16_t srcport; /* TCP/UDP source port number (.e.g, FTP, Telnet, etc.,or equivalent) */ u_int16_t dstport; /* TCP/UDP destination port number (.e.g, FTP, Telnet, etc.,or equivalent) */ u_int8_t flags; /* Shortcut mode(dest only,src only,full flows*/ u_int8_t tcp_flags; /* Cumulative OR of tcp flags */ u_int8_t proto; /* IP protocol, e.g., 6=TCP, 17=UDP, etc... */ u_int8_t tos; /* IP Type-of-Service */ u_int16_t dst_as; /* dst peer/origin Autonomous System */ u_int16_t src_as; /* source peer/origin Autonomous System */ u_int8_t dst_mask; /* destination route's mask bits */ u_int8_t src_mask; /* source route's mask bits */ u_int16_t pad2; /* pad to word boundary */ u_int32_t router_sc; /* Router which is shortcut by switch */ }; static void ndpi_search_netflow(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &ndpi_struct->packet; // const u_int8_t *packet_payload = packet->payload; u_int32_t payload_len = packet->payload_packet_len; time_t now; struct timeval now_tv; NDPI_LOG_DBG(ndpi_struct, "search netflow\n"); if((packet->udp != NULL) && (payload_len >= 24)) { u_int16_t version = (packet->payload[0] << 8) + packet->payload[1], uptime_offset; u_int32_t when, *_when; u_int16_t n = (packet->payload[2] << 8) + packet->payload[3], expected_len = 0; switch(version) { case 1: case 5: case 7: case 9: if((n == 0) || (n > 30)) { NDPI_EXCLUDE_PROTO(ndpi_struct, flow); return; } switch(version) { case 1: expected_len = n * sizeof(struct flow_ver1_rec) + 16 /* header */; break; case 5: expected_len = n * sizeof(struct flow_ver5_rec) + 24 /* header */; break; case 7: expected_len = n * sizeof(struct flow_ver7_rec) + 24 /* header */; break; case 9: /* We need to check the template */ break; } if((expected_len > 0) && (expected_len != payload_len)) { NDPI_EXCLUDE_PROTO(ndpi_struct, flow); return; } uptime_offset = 8; break; case 10: /* IPFIX */ { u_int16_t ipfix_len = n; if(ipfix_len != payload_len) { NDPI_EXCLUDE_PROTO(ndpi_struct, flow); return; } } uptime_offset = 4; break; default: NDPI_EXCLUDE_PROTO(ndpi_struct, flow); return; } _when = (u_int32_t*)&packet->payload[uptime_offset]; /* Sysuptime */ when = ntohl(*_when); do_gettimeofday(&now_tv); now = now_tv.tv_sec; if(((version == 1) && (when == 0)) || ((when >= 946684800 /* 1/1/2000 */) && (when <= (u_int32_t)now))) { NDPI_LOG_INFO(ndpi_struct, "found netflow\n"); ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_NETFLOW, NDPI_PROTOCOL_UNKNOWN, NDPI_CONFIDENCE_DPI); return; } } else NDPI_EXCLUDE_PROTO(ndpi_struct, flow); } void init_netflow_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id) { ndpi_set_bitmask_protocol_detection("NetFlow", ndpi_struct, *id, NDPI_PROTOCOL_NETFLOW, ndpi_search_netflow, NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_UDP_WITH_PAYLOAD, SAVE_DETECTION_BITMASK_AS_UNKNOWN, ADD_TO_DETECTION_BITMASK); *id += 1; }