please find enclosed my contribution that allows snort to be activated over NetFlow. Basically snort can now act as a NetFlow v5 collector (add -5 <port> to tell snort to wait incoming flows on the <port> [note that -i has no effect if -5 is specified]) and run the signatures over the incoming flows. The main difference between runnins snort over NetFlow with respect to pcap is that with NetFlow you have no payload access so basically all the payload signatures are not activated. So you can detect a portscan but you cannot detect a SSH exploit.
Enjoy, Luca
-- Luca Deri <[EMAIL PROTECTED]> http://luca.ntop.org/ Hacker: someone who loves to program and enjoys being clever about it - Richard Stallman
--- 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 <port> Listen on <port> for incoming NetFlow v5 flows
(no pcap is used)\n");
FPUTS_BOTH (" -? Show this information\n");
FPUTS_BOTH ("<Filter Options> are standard BPF options, as seen in TCPDump\n");
@@ -766,11 +768,11 @@
#ifndef WIN32
/* Unix does not support an argument to -s <wink marty!> 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; i<numFlows; i++) {
+ struct flow_ver5_rec *record = &the5Record.flowRecord[i];
+
+ memset(&p, 0, sizeof(p));
+
+ pkth.ts.tv_sec = ntohl(record->Last), 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 <[EMAIL PROTECTED]>
+**
+** 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__ */
