--- snort-2.1.2/src/util.c 2004-03-31 20:09:46.000000000 +0200 +++ snort-2.1.2-netflow/src/util.c 2004-04-08 15:59:46.000000000 +0200 @@ -893,6 +893,7 @@ } else { + if(pv.netflow_port == 0) { /* collect the packet stats */ if(pcap_stats(pd, &ps)) { @@ -918,6 +919,34 @@ { LogMessage(".\n"); } + } + } else { + LogMessage("\n\n====================================" + "===========================================\n"); + LogMessage("Snort analyzed %u packets/%u flows NetFlow\n" + "====================================" + "===========================================\n", + pc.netflow_pkts, pc.netflow_flows); + + recv = pc.tcp+pc.udp+pc.icmp+pc.other; + drop = 0; + } + + LogMessage("\n\n====================================" + "===========================================\n"); + LogMessage("Snort analyzed %u out of %u packets, ", + ps.ps_recv, ps.ps_recv+ps.ps_drop); + + if(ps.ps_recv) + { + LogMessage("dropping %u(%.3f%%) packets\n\n", + ps.ps_drop, + CalcPct( (float) ps.ps_drop, (float) (ps.ps_recv+ps.ps_drop) )); + } + else + { + LogMessage(".\n"); + } LogMessage("Breakdown by protocol: Action Stats:\n"); LogMessage(" TCP: %-10lu (%.3f%%)%-*sALERTS: %-10lu\n", @@ -985,7 +1014,6 @@ LogMessage("==============================================" "=================================\n"); } - } return; } --- snort-2.1.2/src/snort.c 2004-02-04 20:51:12.000000000 +0100 +++ snort-2.1.2-netflow/src/snort.c 2004-04-08 16:01:29.000000000 +0200 @@ -71,6 +71,7 @@ #include "fpdetect.h" #include "sfthreshold.h" #include "packet_time.h" +#include "netflow.h" #include "src/preprocessors/flow/flow_print.h" #include "src/detection-plugins/sp_flowbits.h" @@ -714,6 +715,7 @@ FPUTS_BOTH (" -X Dump the raw packet data starting at the link layer\n"); FPUTS_BOTH (" -y Include year in timestamp in the alert and log files\n"); FPUTS_BOTH (" -z Set assurance mode, match on established sesions (for TCP)\n"); + FPUTS_BOTH (" -5 Listen on for incoming NetFlow v5 flows (no pcap is used)\n"); FPUTS_BOTH (" -? Show this information\n"); FPUTS_BOTH (" are standard BPF options, as seen in TCPDump\n"); @@ -766,11 +768,11 @@ #ifndef WIN32 /* Unix does not support an argument to -s OR -E, -W */ - valid_options = "?A:bB:c:CdDefF:g:h:i:Ik:l:L:m:n:NoOpP:qr:R:sS:t:Tu:UvVwXyz"; + valid_options = "?A:bB:c:CdDefF:g:h:i:Ik:l:L:m:n:NoOpP:qr:R:sS:t:Tu:UvVwXyz5:"; #else /* Win32 does not support: -D, -g, -m, -t, -u */ /* Win32 no longer supports an argument to -s, either! */ - valid_options = "?A:bB:c:CdeEfF:h:i:Ik:l:L:n:NoOpP:qr:R:sS:TUvVwWXyz"; + valid_options = "?A:bB:c:CdeEfF:h:i:Ik:l:L:n:NoOpP:qr:R:sS:TUvVwWXyz5:"; #endif /* loop through each command line var and process it */ @@ -1255,6 +1257,12 @@ pv.assurance_mode = ASSURE_EST; break; + case '5': + DEBUG_WRAP(DebugMessage(DEBUG_INIT, "NetFlow v5 support " + "activated\n");); + pv.netflow_port = atoi(optarg); + break; + case '?': /* show help and exit */ DisplayBanner(); ShowUsage(progname); @@ -1577,17 +1585,119 @@ bzero((char *) &tz, sizeof(tz)); gettimeofday(&starttime, &tz); - /* Read all packets on the device. Continue until cnt packets read */ - if(pcap_loop(pd, pv.pkt_cnt, (pcap_handler) ProcessPacket, NULL) < 0) - { - if(pv.daemon_flag) + if(pv.netflow_port > 0) { + int inSocket, len; + struct sockaddr_in sockIn; + char buffer[1600]; + int sockopt = 1; + + inSocket = socket(AF_INET, SOCK_DGRAM, 0); + + setsockopt(inSocket, SOL_SOCKET, SO_REUSEADDR,(char *)&sockopt, sizeof(sockopt)); + + sockIn.sin_family = AF_INET; + sockIn.sin_port =(int)htons(pv.netflow_port); + sockIn.sin_addr.s_addr = INADDR_ANY; + + if(bind(inSocket,(struct sockaddr *)&sockIn, sizeof(sockIn)) < 0) { + FatalError("NetFlow collector port %d already in use", pv.netflow_port); + close(inSocket); + exit(0); + } else + LogMessage("NetFlow listening on port %d\n", pv.netflow_port); + + while(inSocket > 0) { + struct sockaddr_in fromHost; + int bufferLen; + + len = sizeof(fromHost); + if((bufferLen = recvfrom(inSocket,(char*)&buffer, sizeof(buffer), + 0,(struct sockaddr*)&fromHost, &len)) > 0) { + NetFlow5Record the5Record; + + + memcpy(&the5Record, buffer, bufferLen > sizeof(the5Record) ? sizeof(the5Record): bufferLen); + + if(ntohs(the5Record.flowHeader.version) == 5) { + int i, numFlows = ntohs(the5Record.flowHeader.count); + Packet p; + struct pcap_pkthdr pkth; + IPHdr iph; + TCPHdr tcph; + UDPHdr udph; + + if(numFlows > CONST_V5FLOWS_PER_PAK) numFlows = CONST_V5FLOWS_PER_PAK; + + pc.netflow_pkts++, pc.netflow_flows += numFlows; + DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Received %d flows\n", numFlows);); + + for(i=0; iLast), pkth.ts.tv_usec = 0, + pkth.caplen = 255 /* DUMMY */, pkth.len = 255 /* DUMMY */; + p.pkth = &pkth; + p.iph = &iph; + + iph.ip_verhl = 0x45 /* IPv4 */; + iph.ip_len = 1024; /* DUMMY */ + iph.ip_ttl = 64; /* DUMMY */ + iph.ip_len = htons(64); + iph.ip_proto = record->prot; + iph.ip_src.s_addr = record->srcaddr; + iph.ip_dst.s_addr = record->dstaddr; + + switch(record->prot) { + case IPPROTO_ICMP: + pc.icmp += ntohl(record->dOctets); + break; + case IPPROTO_TCP: + pc.tcp += ntohl(record->dOctets); + p.tcph = &tcph; + tcph.th_sport = record->srcport; + tcph.th_dport = record->dstport; + tcph.th_flags = record->tcp_flags; + + if(tcph.th_flags && TH_ACK) tcph.th_ack = 0x1234; /* DUMMY */ + tcph.th_win = 32768; /* DUMMY */ + tcph.th_offx2 = 0xb0; /* DUMMY */ + p.sp = ntohs(record->srcport), p.dp = ntohs(record->dstport); + break; + case IPPROTO_UDP: + pc.udp += ntohl(record->dOctets); + p.udph = &udph; + udph.uh_sport = record->srcport; + udph.uh_dport = record->dstport; + udph.uh_len = htons(ntohl(record->dOctets)/ntohl(record->dPkts)); + p.sp = ntohs(record->srcport), p.dp = ntohs(record->dstport); + break; + default: + pc.other += ntohl(record->dOctets); + break; + } + + DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Processing flow %d/%d\n", i, numFlows);); + Preprocess(&p); + } + } + } + } + + close(inSocket); + } else { + /* Read all packets on the device. Continue until cnt packets read */ + if(pcap_loop(pd, pv.pkt_cnt, (pcap_handler) ProcessPacket, NULL) < 0) + { + if(pv.daemon_flag) syslog(LOG_CONS | LOG_DAEMON, "pcap_loop: %s", pcap_geterr(pd)); - else + else ErrorMessage("pcap_loop: %s\n", pcap_geterr(pd)); - - CleanExit(1); + + CleanExit(1); + } } - gettimeofday(&endtime, &tz); TIMERSUB(&endtime, &starttime, &difftime); --- snort-2.1.2/src/snort.h 2004-03-31 20:09:46.000000000 +0200 +++ snort-2.1.2-netflow/src/snort.h 2004-04-08 15:55:14.000000000 +0200 @@ -196,6 +196,7 @@ u_int32_t obfuscation_net; u_int32_t obfuscation_mask; int alert_mode; + u_short netflow_port; int log_plugin_active; int alert_plugin_active; u_int32_t log_bitmap; @@ -233,6 +234,7 @@ u_long ipv6; u_long ipx; u_long discards; + u_long netflow_pkts, netflow_flows; u_long alert_pkts; u_long log_pkts; u_long pass_pkts; --- snort-2.1.2/src/netflow.h 1970-01-01 01:00:00.000000000 +0100 +++ snort-2.1.2-netflow/src/netflow.h 2004-04-08 16:01:59.000000000 +0200 @@ -0,0 +1,72 @@ +/* +** Copyright (C) 2004 Luca Deri +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program 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 General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#ifndef __NETFLOW_H__ +#define __NETFLOW_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* ********************************* */ + +#define CONST_V5FLOWS_PER_PAK 30 + +struct flow_ver5_hdr { + u_int16_t version; /* Current version=5*/ + u_int16_t count; /* The number of records in PDU. */ + u_int32_t sysUptime; /* Current time in msecs since router booted */ + u_int32_t unix_secs; /* Current seconds since 0000 UTC 1970 */ + u_int32_t unix_nsecs; /* Residual nanoseconds since 0000 UTC 1970 */ + u_int32_t flow_sequence; /* Sequence number of total flows seen */ + u_int8_t engine_type; /* Type of flow switching engine (RP,VIP,etc.)*/ + u_int8_t engine_id; /* Slot number of the flow switching engine */ +}; + +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 prot; /* 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 */ +}; + +typedef struct single_flow_ver5_rec { + struct flow_ver5_hdr flowHeader; + struct flow_ver5_rec flowRecord[CONST_V5FLOWS_PER_PAK+1 /* safe against buffer overflows */]; +} NetFlow5Record; + +#endif /* __NETFLOW_H__ */