-*.[oac]
+*.[oa]
*.deps/
*.la
*.libs/
+Pending - build 153
+
+-- added DAQs for socket, user, and file in extras
+-- changed -K to -L (log type)
+-- added extra DAQ for user and file
+-- added stream_user for payload processing
+-- added stream_file for file processing
+
15/05/15 - build 152
-- fixed config error for inspection of rebuilt packets
src/stream/icmp/Makefile \
src/stream/tcp/Makefile \
src/stream/udp/Makefile \
+src/stream/user/Makefile \
+src/stream/file/Makefile \
src/network_inspectors/Makefile \
src/network_inspectors/arp_spoof/Makefile \
src/network_inspectors/binder/Makefile \
)
set (UNBUILT_SOURCES
+ daq.txt
differences.txt
errors.txt
enviro.txt
unbuilt_sources = \
snort_manual.txt \
config_changes.txt \
+daq.txt \
differences.txt \
enviro.txt \
errors.txt \
change -> rule_state: 'enabled' ==> 'enable'
change -> sfportscan: 'proto' ==> 'protos'
change -> sfportscan: 'scan_type' ==> 'scan_types'
+change -> smtp: 'ports' ==> 'bindings'
change -> ssh: 'server_ports' ==> 'bindings'
change -> stream5_global: 'max_active_responses' ==> 'max_responses'
change -> stream5_global: 'max_icmp' ==> 'max_sessions'
deleted -> sfportscan: 'detect_ack_scans'
deleted -> sfportscan: 'disabled'
deleted -> sfportscan: 'logfile'
+deleted -> smtp: 'alert_unknown_cmds'
+deleted -> smtp: 'disabled'
+deleted -> smtp: 'enable_mime_decoding'
+deleted -> smtp: 'inspection_type'
+deleted -> smtp: 'max_mime_depth'
+deleted -> smtp: 'max_mime_mem'
+deleted -> smtp: 'memcap'
+deleted -> smtp: 'no_alerts'
+deleted -> smtp: 'print_cmds'
deleted -> ssh: 'autodetect'
deleted -> ssh: 'enable_badmsgdir'
deleted -> ssh: 'enable_paysize'
--- /dev/null
+The Data AcQuisition library (DAQ), provides pluggable packet I/O. The DAQ
+replaces direct calls to libraries like libpcap with an abstraction layer
+that facilitates operation on a variety of hardware and software interfaces
+without requiring changes to Snort. It is possible to select the DAQ type
+and mode when invoking Snort to perform pcap readback or inline operation,
+etc. The DAQ library may be useful for other packet processing
+applications and the modular nature allows you to build new modules for
+other platforms.
+
+The DAQ library is provided as an external package on snort.org. There are
+a few additional modules provided with Snort++. This section summarizes
+the important things you need to know to use these DAQ modules. There are
+also 3rd DAQ modules available.
+
+
+=== Building the DAQ Library and DAQ Modules
+
+The DAQ is bundled with Snort but must be built first using these steps:
+
+ ./configure
+ make
+ sudo make install
+
+This will build and install both static and dynamic DAQ modules.
+
+Note that pcap >= 1.0.0 is required. pcap 1.1.1 is available at the time
+of this writing and is recommended.
+
+Also, libdnet is required for IPQ and NFQ DAQs. If you get a relocation error
+trying to build those DAQs, you may need to reinstall libdnet and configure it
+with something like this:
+
+ ./configure "CFLAGS=-fPIC -g -O2"
+
+You may also experience problems trying to find the dynamic dnet library
+because it isn't always named properly. Try creating a link to the shared
+library (identified by its .x or .x.y etc. extension) with the same name but
+with ".so" inserted as follows:
+
+ $ ln -s libdnet.1.1 libdnet.so.1.1
+ $ ldconfig -Rv /usr/local/lib 2>&1 | grep dnet
+ Adding /usr/local/lib/libdnet.so.1.1
+
+Alternatively, you should be able to fix both issues as follows:
+
+ libtoolize --copy --force
+ aclocal -I config
+ autoheader
+ autoconf
+ automake --foreign
+
+When the DAQ library is built, both static and dynamic flavors will be
+generated. The various DAQ modules will be built if the requisite headers and
+libraries are available. You can disable individual modules, etc. with options
+to configure. For the complete list of configure options, run:
+
+ ./configure --help
+
+
+=== PCAP Module
+
+pcap is the default DAQ. If snort is run w/o any DAQ arguments, it will
+operate as it always did using this module. These are equivalent:
+
+ ./snort -i <device>
+ ./snort -r <file>
+
+ ./snort --daq pcap --daq-mode passive -i <device>
+ ./snort --daq pcap --daq-mode read-file -r <file>
+
+You can specify the buffer size pcap uses with:
+
+ ./snort --daq pcap --daq-var buffer_size=<#bytes>
+
+* The pcap DAQ does not count filtered packets. *
+
+
+=== AFPACKET Module
+
+afpacket functions similar to the pcap DAQ but with better performance:
+
+ ./snort --daq afpacket -i <device>
+ [--daq-var buffer_size_mb=<#MB>]
+ [--daq-var debug]
+
+If you want to run afpacket in inline mode, you must craft the device string as
+one or more interface pairs, where each member of a pair is separated by a
+single colon and each pair is separated by a double colon like this:
+
+ eth0:eth1
+
+or this:
+
+ eth0:eth1::eth2:eth3
+
+By default, the afpacket DAQ allocates 128MB for packet memory. You can change
+this with:
+
+ --daq-var buffer_size_mb=<#MB>
+
+Note that the total allocated is actually higher, here's why. Assuming the
+default packet memory with a snaplen of 1518, the numbers break down like this:
+
+* The frame size is 1518 (snaplen) + the size of the AFPacket header (66
+ bytes) = 1584 bytes.
+
+* The number of frames is 128 MB / 1518 = 84733.
+
+* The smallest block size that can fit at least one frame is 4 KB = 4096 bytes
+ @ 2 frames per block.
+
+* As a result, we need 84733 / 2 = 42366 blocks.
+
+* Actual memory allocated is 42366 * 4 KB = 165.5 MB.
+
+NOTE: Linux kernel version 2.6.31 or higher is required for the AFPacket DAQ
+module due to its dependency on both TPACKET v2 and PACKET_TX_RING support.
+
+
+=== NFQ Module
+
+NFQ is the new and improved way to process iptables packets:
+
+ ./snort --daq nfq \
+ [--daq-var device=<dev>] \
+ [--daq-var proto=<proto>] \
+ [--daq-var queue=<qid>]
+
+ <dev> ::= ip | eth0, etc; default is IP injection
+ <proto> ::= ip4 | ip6 |; default is ip4
+ <qid> ::= 0..65535; default is 0
+
+This module can not run unprivileged so ./snort -u -g will produce a warning
+and won't change user or group.
+
+Notes on iptables are given below.
+
+
+=== IPQ Module
+
+IPQ is the old way to process iptables packets. It replaces the inline version
+available in pre-2.9 versions built with this:
+
+ ./configure --enable-inline
+
+Note that layer 2 resets are not supported with the IPQ DAQ:
+
+ config layer2resets[: <mac>]
+
+Start the IPQ DAQ as follows:
+
+ ./snort --daq ipq \
+ [--daq-var device=<dev>] \
+ [--daq-var proto=<proto>] \
+
+ <dev> ::= ip | eth0, etc; default is IP injection
+ <proto> ::= ip4 | ip6; default is ip4
+
+This module can not run unprivileged so ./snort -u -g will produce a warning
+and won't change user or group.
+
+Notes on iptables are given below.
+
+
+=== IPFW Module
+
+IPFW is available for BSD systems. It replaces the inline version available in
+pre-2.9 versions built with this:
+
+ ./configure --enable-ipfw
+
+This command line argument is no longer supported:
+
+ ./snort -J <port#>
+
+Instead, start Snort like this:
+
+ ./snort --daq ipfw [--daq-var port=<port>]
+
+ <port> ::= 1..65535; default is 8000
+
+* IPFW only supports ip4 traffic.
+
+Notes on FreeBSD and OpenBSD are given below.
+
+
+=== Dump Module
+
+The dump DAQ allows you to test the various inline mode features available in
+2.9 Snort like injection and normalization.
+
+ ./snort -i <device> --daq dump
+ ./snort -r <pcap> --daq dump
+
+By default a file named inline-out.pcap will be created containing all packets
+that passed through or were generated by snort. You can optionally specify a
+different name.
+
+ ./snort --daq dump --daq-var file=<name>
+
+dump uses the pcap daq for packet acquisition. It therefore does not count
+filtered packets (a pcap limitation).
+
+Note that the dump DAQ inline mode is not an actual inline mode. Furthermore,
+you will probably want to have the pcap DAQ acquire in another mode like this:
+
+ ./snort -r <pcap> -Q --daq dump --daq-var load-mode=read-file
+ ./snort -i <device> -Q --daq dump --daq-var load-mode=passive
+
+
+=== Netmap Module
+
+The netmap project is a framework for very high speed packet I/O. It is
+available on both FreeBSD and Linux with varying amounts of preparatory
+setup required. Specific notes for each follow.
+
+ ./snort --daq netmap -i <device>
+ [--daq-var debug]
+
+If you want to run netmap in inline mode, you must craft the device string as
+one or more interface pairs, where each member of a pair is separated by a
+single colon and each pair is separated by a double colon like this:
+
+ em1:em2
+
+or this:
+
+ em1:em2::em3:em4
+
+Inline operation performs Layer 2 forwarding with no MAC filtering, akin to the
+AFPacket module's behavior. All packets received on one interface in an inline
+pair will be forwarded out the other interface unless dropped by the reader and
+vice versa.
+
+IMPORTANT: The interfaces will need to be up and in promiscuous mode in order to
+function ('ifconfig em1 up promisc'). The DAQ module does not currently do
+either of these configuration steps for itself.
+
+==== FreeBSD
+
+In FreeBSD 10.0, netmap has been integrated into the core OS. In order to use
+it, you must recompile your kernel with the line
+
+ device netmap
+
+added to your kernel config.
+
+==== Linux
+
+You will need to download the netmap source code from the project's repository:
+
+ https://code.google.com/p/netmap/
+
+Follow the instructions on the project's homepage for compiling and installing
+the code:
+
+ http://info.iet.unipi.it/~luigi/netmap/
+
+It will involve a standalone kernel module (netmap_lin) as well as patching and
+rebuilding the kernel module used to drive your network adapters. The following
+drivers are supported under Linux at the time of writing (June 2014):
+
+ e1000
+ e1000e
+ forcedeth
+ igb
+ ixgbe
+ r8169
+ virtio
+
+TODO:
+
+* Support for attaching to only a single ring (queue) on a network adapter.
+
+* Support for VALE and netmap pipes.
+
+
+=== Notes on iptables
+
+These notes are just a quick reminder that you need to set up iptables to use
+the IPQ or NFQ DAQs. Doing so may cause problems with your network so tread
+carefully. The examples below are intentionally incomplete so please read the
+related documentation first.
+
+Here is a blog post by Marty for historical reference:
+
+ http://archives.neohapsis.com/archives/snort/2000-11/0394.html
+
+You can check this out for queue sizing tips:
+
+ http://www.inliniac.net/blog/2008/01/23/improving-snort_inlines-nfq-performance.html
+
+You might find useful IPQ info here:
+
+ http://snort-inline.sourceforge.net/
+
+Use this to examine your iptables:
+
+ sudo /sbin/iptables -L
+
+Use something like this to set up NFQ:
+
+ sudo /sbin/iptables
+ -I <table> [<protocol stuff>] [<state stuff>]
+ -j NFQUEUE --queue-num 1
+
+Use something like this to set up IPQ:
+
+ sudo iptables -I FORWARD -j QUEUE
+
+Use something like this to "disconnect" snort:
+
+ sudo /sbin/iptables -D <table> <rule pos>
+
+Be sure to start Snort prior to routing packets through NFQ with iptables.
+Such packets will be dropped until Snort is started.
+
+The queue-num is the number you must give Snort.
+
+If you are running on a system with both NFQ and IPQ support, you may
+experience some start-up failures of the sort:
+
+The solution seems to be to remove both modules from the kernel like this:
+
+ modprobe -r nfnetlink_queue
+ modprobe -r ip_queue
+
+and then install the module you want:
+
+ modprobe ip_queue
+
+or:
+
+ modprobe nfnetlink_queue
+
+These DAQs should be run with a snaplen of 65535 since the kernel defrags the
+packets before queuing. Also, no need to configure frag3.
+
+
+=== Notes on FreeBSD::IPFW
+
+Check the online manual at:
+
+ http://www.freebsd.org/doc/handbook/firewalls-ipfw.html.
+
+Here is a brief example to divert icmp packets to Snort at port 8000:
+
+To enable support for divert sockets, place the following lines in the
+kernel configuration file:
+
+ options IPFIREWALL
+ options IPDIVERT
+
+(The file in this case was: /usr/src/sys/i386/conf/GENERIC; which is platform
+dependent.)
+
+You may need to also set these to use the loadable kernel modules:
+
+ /etc/rc.conf:
+ firewall_enable="YES"
+
+ /boot/loader.conf:
+ ipfw_load="YES"
+ ipdivert_load="YES"
+
+ $ dmesg | grep ipfw
+ ipfw2 (+ipv6) initialized, divert loadable, nat loadable, rule-based
+ forwarding disabled, default to deny, logging disabled
+
+ $ kldload -v ipdivert
+ Loaded ipdivert, id=4
+
+ $ ipfw add 75 divert 8000 icmp from any to any
+ 00075 divert 8000 icmp from any to any
+
+ $ ipfw list
+ ...
+ 00075 divert 8000 icmp from any to any
+ 00080 allow icmp from any to any
+ ...
+
+* Note that on FreeBSD, divert sockets don't work with bridges!
+
+Please refer to the following articles for more information:
+
+* https://forums.snort.org/forums/support/topics/snort-inline-on-freebsd-ipfw
+
+* http://freebsd.rogness.net/snort_inline/
+
+NAT gateway can be used with divert sockets if the network environment is
+conducive to using NAT.
+
+The steps to set up NAT with ipfw are as follows:
+
+1. Set up NAT with two interface em0 and em1 by adding the following to
+/etc/rc.conf. Here em0 is connected to external network and em1 to
+host-only LAN.
+
+ gateway_enable="YES"
+ natd_program="/sbin/natd" # path to natd
+ natd_enable="YES" # Enable natd (if firewall_enable == YES)
+ natd_interface="em0" # Public interface or IP Address
+ natd_flags="-dynamic" # Additional flags
+ defaultrouter=""
+ ifconfig_em0="DHCP"
+ ifconfig_em1="inet 192.168.1.2 netmask 255.255.255.0"
+ firewall_enable="YES"
+ firewall_script="/etc/rc.firewall"
+ firewall_type="simple"
+
+2. Add the following divert rules to divert packets to Snort above and
+below the NAT rule in the "Simple" section of /etc/rc.firewall.
+
+ ...
+ # Inspect outbound packets (those arriving on "inside" interface)
+ # before NAT translation.
+ ${fwcmd} add divert 8000 all from any to any in via ${iif}
+ case ${natd_enable} in
+ [Yy][Ee][Ss])
+ if [ -n "${natd_interface}" ]; then
+ ${fwcmd} add divert natd all from any to any via ${natd_interface}
+ fi
+ ;;
+ esac
+ ...
+ # Inspect inbound packets (those arriving on "outside" interface)
+ # after NAT translation that aren't blocked for other reasons,
+ # after the TCP "established" rule.
+ ${fwcmd} add divert 8000 all from any to any in via ${oif}
+
+
+=== Notes on OpenBSD::IPFW
+
+OpenBSD supports divert sockets as of 4.7, so we use the ipfw DAQ.
+
+Here is one way to set things up:
+
+1. Configure the system to forward packets:
+
+ $ sysctl net.inet.ip.forwarding=1
+ $ sysctl net.inet6.ip6.forwarding=1
+
+ (You can also put that in /etc/sysctl.conf to enable on boot.)
+
+2. Set up interfaces
+
+ $ dhclient vic1
+ $ dhclient vic2
+
+3. Set up packet filter rules:
+
+ $ echo "pass out on vic1 divert-packet port 9000 keep-state" > rules.txt
+ $ echo "pass out on vic2 divert-packet port 9000 keep-state" >> rules.txt
+
+ $ pfctl -v -f rules.txt
+
+4. Analyze packets diverted to port 9000:
+
+ $ ./snort --daq ipfw --daq-var port=9000
+
+* Note that on OpenBSD, divert sockets don't work with bridges!
+
+
+=== Socket Module
+
+The socket module provides provides a stream socket server that will accept
+up to 2 simultaneous connections and bridge them together while also
+passing data to Snort++ for inspection. The first connection accepted is
+considered the client and the second connection accepted is considered the
+server. If there is only one connection, stream data can't be forwarded
+but it is still inspected.
+
+Each read from a socket of up to snaplen bytes is passed as a packet to
+Snort++ along with a DAQ_SktHdr_t pointer in DAQ_PktHdr_t->priv_ptr.
+DAQ_SktHdr_t conveys IP4 address, ports, protocol, and direction. Socket
+packets can be configured to be TCP or UDP. The socket DAQ can be operated
+in inline mode and is able to block packets.
+
+The socket DAQ uses DLT_SOCKET and requires that Snort++ load the socket
+codec which is included in the extra package.
+
+To use the socket DAQ, start Snort++ like this:
+
+ ./snort --plugin-path /path/to/lib/snort_extra \
+ --daq socket [--daq-var port=<port>] [--daq-var proto=<proto>] [-Q]
+
+ <port> ::= 1..65535; default is 8000
+ <proto> ::= tcp | udp
+
+* This module only supports ip4 traffic.
+
+* This module is only supported by Snort++. It is not compatible with
+ Snort.
+
+* This module is primarily for development and test.
+
+
+=== File Module
+
+The file module provides the ability to process files directly w/o having
+to extract them from pcaps. Use the file module with Snort's stream_file
+to get file type identification and signature services. The usual IPS
+detection and logging etc. is available too.
+
+You can process all the files in a directory recursively using 8 threads
+with these Snort options:
+
+ --pcap-dir path -z 8
+
+* This module is only supported by Snort++. It is not compatible with
+ Snort.
+
+* This module is primarily for development and test.
+
+
+=== User Module
+
+The user module generates packets suitable for processing with Snort's
+stream_user from simple text input. The first character of the line
+determines it's purpose:
+
+ '$' command
+ '#' comment
+ '"' quoted string packet data
+ 'x' hex packet data
+ ' ' empty line separates packets
+
+The available commands are:
+
+ $client <ip4> <port>
+ $server <ip4> <port>
+
+ $packet -> client
+ $packet -> server
+
+ $packet <addr> <port> -> <addr> <port>
+
+Client and server are determined as follows. $packet -> client indicates
+to the client (from server) and $packet -> server indicates a packet to the
+server (from client). $packet followed by a 4-tuple uses the heuristic
+that the client is the side with the lower port number.
+
+The default client and server are 192.168.1.1 12345 and 10.1.2.3 80
+respectively. $packet commands with a 4-tuple do not change client and
+server set with the other $packet commands.
+
+$packet commands should be followed by packet data, which may contain any
+combination of hex and strings. Data for a packet ends with the next
+command or a blank line. Data after a blank line will start another packet
+with the same tuple as the prior one.
+
+Strings may contain the following escape sequences:
+
+ \r = 0x0D = carriage return
+ \n = 0x0A = new line
+ \t = 0x09 = tab
+ \\ = 0x5C = \
+
+Format your input carefully; there is minimal error checking and little
+tolerance for arbitrary whitespace. You can use Snort's -L user option to
+generate user input from a pcap.
+
+* This module only supports ip4 traffic.
+
+* This module is only supported by Snort++. It is not compatible with
+ Snort.
+
+* This module is primarily for development and test.
+
include::logger.txt[]
+== DAQ Modules
+
+include::daq.txt[]
+
== Snort++ vs Snort
include::differences.txt[]
# Use the same defines Snort used
# (absolutely critical to ensure struct definitions match)
CXXFLAGS=`pkg-config --cflags snort`
+CFLAGS=`pkg-config --cflags snort`
+AM_CPPFLAGS=`pkg-config --cflags-only-I snort`
+CFLAGS="$CFLAGS -std=c99"
+AM_CFLAGS="-std=c99"
AM_CXXFLAGS="-std=c++11"
AX_CXX_COMPILE_STDCXX_11
])
CC_VISIBILITY()
-# Checks for libraries.
AC_ARG_WITH(snort-includes,
- [ --with-snort-includes=DIR snort include directory],
- [with_snort_includes="$withval"], [with_snort_includes="no"])
+ AC_HELP_STRING([--with-snort-includes=DIR],[snort include directory]),
+ [with_snort_includes="$withval"],[with_snort_includes="no"])
if test "x$with_snort_includes" != "xno"; then
AM_CPPFLAGS="${AM_CPPFLAGS} -I${with_snort_includes}"
Makefile \
src/Makefile \
src/codecs/Makefile \
+ src/daqs/Makefile \
src/inspectors/Makefile \
src/ips_options/Makefile \
src/loggers/Makefile \
add_subdirectory (codecs)
+add_subdirectory (daqs)
add_subdirectory (inspectors)
add_subdirectory (ips_options)
add_subdirectory (loggers)
SUBDIRS = \
codecs \
+daqs \
inspectors \
ips_options \
loggers \
-###################################
-####### adding pim library #######
-###################################
-
-
add_example_library(pim codecs pim.cc)
-
-
-
-###################################
-#### adding Token ring library ####
-###################################
-
+add_example_library(socket codecs socket.cc)
add_example_library(token_ring codecs token_ring.cc)
AUTOMAKE_OPTIONS=foreign
-ehlibdir = $(pkglibdir)/codecs
-ehlib_LTLIBRARIES = libpim.la
+cdlibdir = $(pkglibdir)/codecs
+
+cdlib_LTLIBRARIES = libpim.la
libpim_la_CXXFLAGS = $(AM_CXXFLAGS)
libpim_la_LDFLAGS = -export-dynamic -shared
libpim_la_SOURCES = pim.cc
-
-ehlib_LTLIBRARIES += libtoken_ring.la
+cdlib_LTLIBRARIES += libtoken_ring.la
libtoken_ring_la_CXXFLAGS = $(AM_CXXFLAGS)
libtoken_ring_la_LDFLAGS = -export-dynamic -shared
libtoken_ring_la_SOURCES = token_ring.cc
+cdlib_LTLIBRARIES += libsocket.la
+libsocket_la_CXXFLAGS = $(AM_CXXFLAGS)
+libsocket_la_LDFLAGS = -export-dynamic -shared
+libsocket_la_SOURCES = socket.cc
+
AM_CXXFLAGS = @AM_CXXFLAGS@
+
--- /dev/null
+diff -ruN -x '*.in' -x '*.git*' -x '*m4*' daq-2.0.4-orig/README daq-2.0.4/README
+--- daq-2.0.4-orig/README 2014-06-19 15:54:07.000000000 -0400
++++ daq-2.0.4/README 2015-05-03 09:26:48.000000000 -0400
+@@ -277,6 +277,40 @@
+ - Support for VALE and netmap pipes.
+
+
++Socket Module
++=============
++
++The socket module provides provides a stream socket server that will accept
++up to 2 simultaneous connections and bridge them together while also
++passing data to Snort++ for inspection. The first connection accepted is
++considered the client and the second connection accepted is considered the
++server. If there is only one connection, stream data can't be forwarded
++but it is still inspected.
++
++Each read from a socket of up to snaplen bytes is passed as a packet to
++Snort++ along with a DAQ_SktHdr_t pointer in DAQ_PktHdr_t->priv_ptr.
++DAQ_SktHdr_t conveys IP4 address, ports, protocol, and direction. Socket
++packets can be configured to be TCP or UDP. The socket DAQ can be operated
++in inline mode and is able to block packets.
++
++The socket DAQ uses DLT_SOCKET and requires that Snort++ load the socket
++codec which is included in the extra package.
++
++To use the socket DAQ, start Snort++ like this:
++
++ ./snort --plugin-path /path/to/lib/snort_extra \
++ --daq socket [--daq-var port=<port>] [--daq-var proto=<proto>] [-Q]
++
++ <port> ::= 1..65535; default is 8000
++ <proto> ::= tcp | udp
++
++* The socket DAQ only supports ip4 traffic.
++* The socket DAQ is only supported by Snort++. It is not compatible with
++ Snort.
++
++This module is primarily for development and test.
++
++
+ Notes on iptables
+ =================
+
+diff -ruN -x '*.in' -x '*.git*' -x '*m4*' daq-2.0.4-orig/api/daq_common.h daq-2.0.4/api/daq_common.h
+--- daq-2.0.4-orig/api/daq_common.h 2014-09-09 15:57:29.000000000 -0400
++++ daq-2.0.4/api/daq_common.h 2015-05-06 15:07:45.000000000 -0400
+@@ -113,6 +113,21 @@
+ uint16_t address_space_id; /* Unique ID of the address space */
+ } DAQ_PktHdr_t;
+
++#define DAQ_SKT_FLAG_TO_SERVER 0x01
++#define DAQ_SKT_FLAG_START_FLOW 0x02
++#define DAQ_SKT_FLAG_END_FLOW 0x04
++
++/* socket DAQ sets priv_ptr to this */
++typedef struct
++{
++ uint32_t src_addr;
++ uint32_t dst_addr;
++ uint16_t src_port;
++ uint16_t dst_port;
++ uint8_t ip_proto;
++ uint8_t flags;
++} DAQ_SktHdr_t;
++
+ #define DAQ_METAHDR_TYPE_SOF 0
+ #define DAQ_METAHDR_TYPE_EOF 1
+ #define DAQ_METAHDR_TYPE_VPN_LOGIN 2
+diff -ruN -x '*.in' -x '*.git*' -x '*m4*' daq-2.0.4-orig/configure.ac daq-2.0.4/configure.ac
+--- daq-2.0.4-orig/configure.ac 2014-08-11 21:18:27.000000000 -0400
++++ daq-2.0.4/configure.ac 2015-02-15 16:05:27.000000000 -0500
+@@ -207,6 +207,13 @@
+ fi
+ AM_CONDITIONAL([BUILD_NETMAP_MODULE], [test "$enable_netmap_module" = yes])
+
++# socket Module
++AC_ARG_ENABLE(socket-module,
++ AC_HELP_STRING([--disable-socket-module],[don't build the bundled socket module]),
++ [enable_socket_module="$enableval"], [enable_socket_module="$DEFAULT_ENABLE"])
++
++AM_CONDITIONAL([BUILD_SOCKET_MODULE], [test "$enable_socket_module" = yes])
++
+ if test "$enable_ipq_module" = yes -o "$enable_nfq_module" = yes ; then
+ AC_CHECK_HEADERS(dnet.h,,DNET_H="no")
+ AC_CHECK_HEADERS(dumbnet.h,,DUMBNET_H="no")
+@@ -297,4 +304,5 @@
+ echo "Build NFQ DAQ module....... : $enable_nfq_module"
+ echo "Build PCAP DAQ module...... : $enable_pcap_module"
+ echo "Build netmap DAQ module...... : $enable_netmap_module"
++echo "Build socket DAQ module...... : $enable_socket_module"
+ echo
+diff -ruN -x '*.in' -x '*.git*' -x '*m4*' daq-2.0.4-orig/os-daq-modules/Makefile.am daq-2.0.4/os-daq-modules/Makefile.am
+--- daq-2.0.4-orig/os-daq-modules/Makefile.am 2014-06-19 15:54:09.000000000 -0400
++++ daq-2.0.4/os-daq-modules/Makefile.am 2015-02-15 16:05:27.000000000 -0500
+@@ -98,6 +98,17 @@
+ libdaq_static_modules_la_CFLAGS += -DBUILD_NETMAP_MODULE
+ endif
+
++if BUILD_SOCKET_MODULE
++if BUILD_SHARED_MODULES
++ pkglib_LTLIBRARIES += daq_socket.la
++ daq_socket_la_SOURCES = daq_socket.c
++ daq_socket_la_CFLAGS = -DBUILDING_SO
++ daq_socket_la_LDFLAGS = -module -export-dynamic -avoid-version -shared @XCCFLAGS@
++endif
++ libdaq_static_modules_la_SOURCES += daq_socket.c
++ libdaq_static_modules_la_CFLAGS += -DBUILD_SOCKET_MODULE
++endif
++
+ INCLUDES = -I$(top_srcdir)/api -I$(top_srcdir)/sfbpf -I$(top_builddir)/sfbpf
+
+ EXTRA_DIST = daq-modules-config.in
+diff -ruN -x '*.in' -x '*.git*' -x '*m4*' daq-2.0.4-orig/os-daq-modules/daq_socket.c daq-2.0.4/os-daq-modules/daq_socket.c
+--- daq-2.0.4-orig/os-daq-modules/daq_socket.c 1969-12-31 19:00:00.000000000 -0500
++++ daq-2.0.4/os-daq-modules/daq_socket.c 2015-05-06 12:10:38.000000000 -0400
+@@ -0,0 +1,586 @@
++/*--------------------------------------------------------------------------
++** Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
++**
++** This program is free software; you can redistribute it and/or modify it
++** under the terms of the GNU General Public License Version 2 as published
++** by the Free Software Foundation. You may not use, modify or distribute
++** this program under any other version of the GNU General Public License.
++**
++** 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.,
++** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
++**--------------------------------------------------------------------------*/
++/* daq_socket.c author Russ Combs <rucombs@cisco.com> */
++
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
++#include <errno.h>
++#include <stdlib.h>
++#include <string.h>
++#include <stdio.h>
++
++#include <sys/types.h>
++#include <sys/time.h>
++#include <sys/unistd.h>
++
++#include <netinet/in.h>
++#include <sys/socket.h>
++#include <netinet/in_systm.h>
++#include <netinet/ip.h>
++
++#include "daq_api.h"
++#include "sfbpf/sfbpf_dlt.h"
++
++#define DAQ_MOD_VERSION 0
++#define DAQ_NAME "socket"
++#define DAQ_TYPE (DAQ_TYPE_INTF_CAPABLE | DAQ_TYPE_INLINE_CAPABLE | DAQ_TYPE_MULTI_INSTANCE)
++#define DEFAULT_PORT 8000
++
++typedef struct {
++ int sock_a; // recv from b
++ int sock_b; // recv from a
++ int sock_c; // connect
++
++ int use_a;
++ int port;
++ int passive;
++ int stop;
++
++ unsigned timeout;
++ unsigned snaplen;
++
++ struct sockaddr_in sin_a;
++ struct sockaddr_in sin_b;
++
++ DAQ_SktHdr_t pci;
++
++ uint8_t* buf;
++ char error[DAQ_ERRBUF_SIZE];
++
++ DAQ_State state;
++ DAQ_Stats_t stats;
++} SockImpl;
++
++//-------------------------------------------------------------------------
++// socket functions
++//-------------------------------------------------------------------------
++
++static int sock_setup(SockImpl* impl)
++{
++ struct sockaddr_in sin;
++
++ if ( (impl->sock_c = socket(PF_INET, SOCK_STREAM, 0)) == -1 )
++ {
++ DPE(impl->error, "%s: can't create listener socket (%s)\n",
++ __FUNCTION__, strerror(errno));
++ return -1;
++ }
++
++ sin.sin_family = PF_INET;
++ sin.sin_addr.s_addr = INADDR_ANY;
++ sin.sin_port = htons(impl->port);
++
++ if ( bind(impl->sock_c, (struct sockaddr*)&sin, sizeof(sin)) == -1 )
++ {
++ DPE(impl->error, "%s: can't bind listener socket (%s)\n",
++ __FUNCTION__, strerror(errno));
++ return -1;
++ }
++
++ if ( listen(impl->sock_c, 2) == -1 )
++ {
++ DPE(impl->error, "%s: can't listen on socket (%s)\n",
++ __FUNCTION__, strerror(errno));
++ return -1;
++ }
++ return 0;
++}
++
++static void sock_cleanup(SockImpl* impl)
++{
++ if ( impl->sock_c >= 0 )
++ close(impl->sock_c);
++
++ if ( impl->sock_a >= 0 )
++ close(impl->sock_a);
++
++ if ( impl->sock_b >= 0 )
++ close(impl->sock_b);
++
++ impl->sock_c = impl->sock_a = impl->sock_b = -1;
++}
++
++static int sock_recv(SockImpl* impl, int* sock, struct sockaddr_in* psin)
++{
++ int n = recv(*sock, impl->buf, impl->snaplen, 0);
++
++ if ( n <= 0 )
++ {
++ if (errno != EINTR)
++ {
++ DPE(impl->error, "%s: can't recv from socket (%s)\n",
++ __FUNCTION__, strerror(errno));
++ *sock = -1;
++ psin->sin_addr.s_addr = 0;
++ psin->sin_port = 0;
++ impl->pci.flags = DAQ_SKT_FLAG_END_FLOW;
++ }
++ return 0;
++ }
++ return n;
++}
++
++static int sock_send(
++ SockImpl* impl, int sock, const uint8_t* buf, uint32_t len)
++{
++ if ( sock < 0 )
++ return 0;
++
++ int n = send(sock, buf, len, 0);
++
++ while ( 0 <= n && (uint32_t)n < len )
++ {
++ buf += n;
++ len -= n;
++ n = send(sock, buf, len, 0);
++ }
++ if ( n == -1 )
++ {
++ DPE(impl->error, "%s: can't send on socket (%s)\n",
++ __FUNCTION__, strerror(errno));
++ return -1;
++ }
++ return 0;
++}
++
++static int sock_accept(SockImpl* impl, int* sock, struct sockaddr_in* psin)
++{
++ const char* banner;
++ socklen_t len = sizeof(*psin);
++ *sock = accept(impl->sock_c, (struct sockaddr*)psin, &len);
++
++ if ( *sock == -1 )
++ {
++ DPE(impl->error, "%s: can't accept incoming connection (%s)\n",
++ __FUNCTION__, strerror(errno));
++ return -1;
++ }
++ banner = impl->use_a ? "client\n" : "server\n";
++ sock_send(impl, *sock, (const uint8_t*)banner, 7);
++
++ impl->pci.flags = DAQ_SKT_FLAG_START_FLOW;
++ return 0;
++}
++
++static int sock_poll(SockImpl* impl, int* sock, struct sockaddr_in* psin)
++{
++ int max_fd;
++ fd_set inputs;
++
++ if ( impl->sock_c < 0 )
++ return 0;
++
++ FD_ZERO(&inputs);
++ FD_SET(impl->sock_c, &inputs);
++ max_fd = impl->sock_c;
++
++ if ( *sock > 0 )
++ {
++ FD_SET(*sock, &inputs);
++
++ if ( *sock > max_fd )
++ max_fd = *sock;
++ }
++
++ struct timeval timeout;
++ timeout.tv_sec = 1;
++ timeout.tv_usec = 0;
++
++ if ( !select(max_fd+1, &inputs, NULL, NULL, &timeout) )
++ return 0;
++
++ else if ( *sock >= 0 && FD_ISSET(*sock, &inputs) )
++ return sock_recv(impl, sock, psin);
++
++ else if ( *sock < 0 && FD_ISSET(impl->sock_c, &inputs) )
++ return sock_accept(impl, sock, psin);
++
++ return 0;
++}
++
++//-------------------------------------------------------------------------
++// daq utilities
++//-------------------------------------------------------------------------
++
++static void set_pkt_hdr(SockImpl* impl, DAQ_PktHdr_t* phdr, ssize_t len)
++{
++ struct timeval t;
++ memset (&t, 0, sizeof(struct timeval));
++ gettimeofday(&t, NULL);
++
++ phdr->ts.tv_sec = t.tv_sec;
++ phdr->ts.tv_usec = t.tv_usec;
++ phdr->caplen = len;
++ phdr->pktlen = len;
++ phdr->ingress_index = -1;
++ phdr->egress_index = -1;
++ phdr->ingress_group = -1;
++ phdr->egress_group = -1;
++ phdr->flags = 0;
++ phdr->address_space_id = 0;
++ phdr->opaque = 0;
++
++ // use_a already toggled
++ if ( impl->use_a )
++ {
++ impl->pci.src_addr = impl->sin_b.sin_addr.s_addr;
++ impl->pci.dst_addr = impl->sin_a.sin_addr.s_addr;
++ impl->pci.src_port = impl->sin_b.sin_port;
++ impl->pci.dst_port = impl->sin_a.sin_port;
++ impl->pci.flags &= ~DAQ_SKT_FLAG_TO_SERVER;
++ }
++ else
++ {
++ impl->pci.src_addr = impl->sin_a.sin_addr.s_addr;
++ impl->pci.dst_addr = impl->sin_b.sin_addr.s_addr;
++ impl->pci.src_port = impl->sin_a.sin_port;
++ impl->pci.dst_port = impl->sin_b.sin_port;
++ impl->pci.flags |= DAQ_SKT_FLAG_TO_SERVER;
++ }
++
++ phdr->priv_ptr = &impl->pci;
++}
++
++// forward all but drops, retries and blacklists:
++static const int s_fwd[MAX_DAQ_VERDICT] = { 1, 0, 1, 1, 0, 1, 0 };
++
++static int socket_daq_process(
++ SockImpl* impl, DAQ_Analysis_Func_t cb, void* user)
++{
++ DAQ_PktHdr_t hdr;
++ int* sock = impl->use_a ? &impl->sock_a : &impl->sock_b;
++ struct sockaddr_in* psin = impl->use_a ? &impl->sin_a : &impl->sin_b;
++ impl->pci.flags = 0;
++
++ int n = sock_poll(impl, sock, psin);
++
++ // don't toggle w/o at least one connection so client is always 1st
++ if ( impl->sock_a > -1 || impl->sock_b > -1 )
++ impl->use_a = !impl->use_a;
++
++ if ( n <= 0 && !impl->pci.flags )
++ return n;
++
++ set_pkt_hdr(impl, &hdr, n);
++ DAQ_Verdict verdict = cb(user, &hdr, impl->buf);
++
++ if ( verdict >= MAX_DAQ_VERDICT )
++ verdict = DAQ_VERDICT_BLOCK;
++
++ impl->stats.verdicts[verdict]++;
++
++ if ( impl->passive || s_fwd[verdict] )
++ {
++ // already toggled use_a, so we get a->b or b->a
++ sock = impl->use_a ? &impl->sock_a : &impl->sock_b;
++ sock_send(impl, *sock, impl->buf, n);
++ }
++ return n;
++}
++
++static int socket_daq_config (
++ SockImpl* impl, const DAQ_Config_t* cfg, char* errBuf, size_t errMax)
++{
++ DAQ_Dict* entry;
++
++ if ( cfg->name )
++ {
++ char* end = NULL;
++ impl->port = (int)strtol(cfg->name, &end, 0);
++ }
++ for ( entry = cfg->values; entry; entry = entry->next)
++ {
++ if ( !entry->value || !*entry->value )
++ {
++ snprintf(errBuf, errMax,
++ "%s: variable needs value (%s)\n", __FUNCTION__, entry->key);
++ return DAQ_ERROR;
++ }
++ else if ( !strcmp(entry->key, "port") )
++ {
++ char* end = entry->value;
++ impl->port = (int)strtol(entry->value, &end, 0);
++
++ if ( *end || impl->port <= 0 || impl->port > 65535 )
++ {
++ snprintf(errBuf, errMax, "%s: bad port (%s)\n",
++ __FUNCTION__, entry->value);
++ return DAQ_ERROR;
++ }
++ }
++ else if ( !strcmp(entry->key, "proto") )
++ {
++ if ( !strcmp(entry->value, "tcp") )
++ impl->pci.ip_proto = IPPROTO_TCP;
++
++ else if ( !strcmp(entry->value, "udp") )
++ impl->pci.ip_proto = IPPROTO_UDP;
++ else
++ {
++ snprintf(errBuf, errMax, "%s: bad proto (%s)\n",
++ __FUNCTION__, entry->value);
++ return DAQ_ERROR;
++ }
++ }
++ else
++ {
++ snprintf(errBuf, errMax,
++ "%s: unsupported variable (%s=%s)\n",
++ __FUNCTION__, entry->key, entry->value);
++ return DAQ_ERROR;
++ }
++ }
++ if ( !impl->pci.ip_proto )
++ impl->pci.ip_proto = IPPROTO_TCP;
++
++ if ( !impl->port )
++ impl->port = DEFAULT_PORT;
++
++ impl->snaplen = cfg->snaplen ? cfg->snaplen : IP_MAXPACKET;
++ impl->timeout = cfg->timeout;
++ impl->passive = ( cfg->mode == DAQ_MODE_PASSIVE );
++
++ return DAQ_SUCCESS;
++}
++
++//-------------------------------------------------------------------------
++// daq
++//-------------------------------------------------------------------------
++
++static void socket_daq_shutdown (void* handle)
++{
++ SockImpl* impl = (SockImpl*)handle;
++
++ if ( impl->buf )
++ free(impl->buf);
++
++ free(impl);
++}
++
++//-------------------------------------------------------------------------
++
++static int socket_daq_initialize (
++ const DAQ_Config_t* cfg, void** handle, char* errBuf, size_t errMax)
++{
++ SockImpl* impl = calloc(1, sizeof(*impl));
++
++ if ( !impl )
++ {
++ snprintf(errBuf, errMax, "%s: failed to allocate the ipfw context!",
++ __FUNCTION__);
++ return DAQ_ERROR_NOMEM;
++ }
++
++ if ( socket_daq_config(impl, cfg, errBuf, errMax) != DAQ_SUCCESS )
++ {
++ socket_daq_shutdown(impl);
++ return DAQ_ERROR;
++ }
++ impl->buf = malloc(impl->snaplen);
++
++ if ( !impl->buf )
++ {
++ snprintf(errBuf, errMax, "%s: failed to allocate the ipfw buffer!",
++ __FUNCTION__);
++ socket_daq_shutdown(impl);
++ return DAQ_ERROR_NOMEM;
++ }
++
++ impl->sock_c = impl->sock_a = impl->sock_b = -1;
++ impl->use_a = 1;
++ impl->state = DAQ_STATE_INITIALIZED;
++
++ *handle = impl;
++ return DAQ_SUCCESS;
++}
++
++//-------------------------------------------------------------------------
++
++static int socket_daq_start (void* handle)
++{
++ SockImpl* impl = (SockImpl*)handle;
++
++ if ( sock_setup(impl) )
++ return DAQ_ERROR;
++
++ impl->state = DAQ_STATE_STARTED;
++ return DAQ_SUCCESS;
++}
++
++static int socket_daq_stop (void* handle)
++{
++ SockImpl* impl = (SockImpl*)handle;
++ sock_cleanup(impl);
++ impl->state = DAQ_STATE_STOPPED;
++ return DAQ_SUCCESS;
++}
++
++//-------------------------------------------------------------------------
++
++static int socket_daq_inject (
++ void* handle, const DAQ_PktHdr_t* hdr, const uint8_t* buf, uint32_t len,
++ int reverse)
++{
++ SockImpl* impl = (SockImpl*)handle;
++ int sock;
++
++ if ( reverse )
++ sock = impl->use_a ? impl->sock_b : impl->sock_a;
++ else
++ sock = impl->use_a ? impl->sock_a : impl->sock_b;
++
++ int status = sock_send(impl, sock, buf, len);
++
++ if ( status )
++ return DAQ_ERROR;
++
++ impl->stats.packets_injected++;
++ return DAQ_SUCCESS;
++}
++
++//-------------------------------------------------------------------------
++
++static int socket_daq_acquire (
++ void* handle, int cnt, DAQ_Analysis_Func_t callback, DAQ_Meta_Func_t metaback, void* user)
++{
++ SockImpl* impl = (SockImpl*)handle;
++ int hit = 0, miss = 0;
++ impl->stop = 0;
++
++ while ( hit < cnt || cnt <= 0 )
++ {
++ int status = socket_daq_process(impl, callback, user);
++
++ if ( status > 0 )
++ {
++ hit++;
++ miss = 0;
++ }
++ else if ( status < 0 )
++ return DAQ_ERROR;
++
++ else if ( ++miss == 2 || impl->stop )
++ break;
++ }
++ return DAQ_SUCCESS;
++}
++
++//-------------------------------------------------------------------------
++
++static int socket_daq_breakloop (void* handle)
++{
++ SockImpl* impl = (SockImpl*)handle;
++ impl->stop = 1;
++ return DAQ_SUCCESS;
++}
++
++static DAQ_State socket_daq_check_status (void* handle)
++{
++ SockImpl* impl = (SockImpl*)handle;
++ return impl->state;
++}
++
++static int socket_daq_get_stats (void* handle, DAQ_Stats_t* stats)
++{
++ SockImpl* impl = (SockImpl*)handle;
++ *stats = impl->stats;
++ return DAQ_SUCCESS;
++}
++
++static void socket_daq_reset_stats (void* handle)
++{
++ SockImpl* impl = (SockImpl*)handle;
++ memset(&impl->stats, 0, sizeof(impl->stats));
++}
++
++static int socket_daq_get_snaplen (void* handle)
++{
++ SockImpl* impl = (SockImpl*)handle;
++ return impl->snaplen;
++}
++
++static uint32_t socket_daq_get_capabilities (void* handle)
++{
++ return DAQ_CAPA_BLOCK | DAQ_CAPA_REPLACE | DAQ_CAPA_INJECT | DAQ_CAPA_INJECT_RAW
++ | DAQ_CAPA_BREAKLOOP | DAQ_CAPA_UNPRIV_START;
++}
++
++static int socket_daq_get_datalink_type(void *handle)
++{
++ return DLT_SOCKET;
++}
++
++static const char* socket_daq_get_errbuf (void* handle)
++{
++ SockImpl* impl = (SockImpl*)handle;
++ return impl->error;
++}
++
++static void socket_daq_set_errbuf (void* handle, const char* s)
++{
++ SockImpl* impl = (SockImpl*)handle;
++ DPE(impl->error, "%s", s ? s : "");
++}
++
++static int socket_daq_get_device_index(void* handle, const char* device)
++{
++ return DAQ_ERROR_NOTSUP;
++}
++
++static int socket_daq_set_filter (void* handle, const char* filter)
++{
++ return DAQ_ERROR_NOTSUP;
++}
++
++//-------------------------------------------------------------------------
++
++#ifdef BUILDING_SO
++DAQ_SO_PUBLIC DAQ_Module_t DAQ_MODULE_DATA =
++#else
++DAQ_Module_t socket_daq_module_data =
++#endif
++{
++ .api_version = DAQ_API_VERSION,
++ .module_version = DAQ_MOD_VERSION,
++ .name = DAQ_NAME,
++ .type = DAQ_TYPE,
++ .initialize = socket_daq_initialize,
++ .set_filter = socket_daq_set_filter,
++ .start = socket_daq_start,
++ .acquire = socket_daq_acquire,
++ .inject = socket_daq_inject,
++ .breakloop = socket_daq_breakloop,
++ .stop = socket_daq_stop,
++ .shutdown = socket_daq_shutdown,
++ .check_status = socket_daq_check_status,
++ .get_stats = socket_daq_get_stats,
++ .reset_stats = socket_daq_reset_stats,
++ .get_snaplen = socket_daq_get_snaplen,
++ .get_capabilities = socket_daq_get_capabilities,
++ .get_datalink_type = socket_daq_get_datalink_type,
++ .get_errbuf = socket_daq_get_errbuf,
++ .set_errbuf = socket_daq_set_errbuf,
++ .get_device_index = socket_daq_get_device_index,
++ .modify_flow = NULL,
++ .hup_prep = NULL,
++ .hup_apply = NULL,
++ .hup_post = NULL,
++};
++
+diff -ruN -x '*.in' -x '*.git*' -x '*m4*' daq-2.0.4-orig/os-daq-modules/daq_static_modules.c daq-2.0.4/os-daq-modules/daq_static_modules.c
+--- daq-2.0.4-orig/os-daq-modules/daq_static_modules.c 2014-06-10 09:38:53.000000000 -0400
++++ daq-2.0.4/os-daq-modules/daq_static_modules.c 2015-02-19 17:22:50.000000000 -0500
+@@ -41,5 +41,8 @@
+ #ifdef BUILD_PCAP_MODULE
+ &pcap_daq_module_data,
+ #endif
++#ifdef BUILD_SOCKET_MODULE
++ &socket_daq_module_data,
++#endif
+ };
+ const int num_static_modules = sizeof(static_modules) / sizeof(static_modules[0]);
+diff -ruN -x '*.in' -x '*.git*' -x '*m4*' daq-2.0.4-orig/os-daq-modules/daq_static_modules.h daq-2.0.4/os-daq-modules/daq_static_modules.h
+--- daq-2.0.4-orig/os-daq-modules/daq_static_modules.h 2014-06-10 09:38:53.000000000 -0400
++++ daq-2.0.4/os-daq-modules/daq_static_modules.h 2015-02-15 16:05:27.000000000 -0500
+@@ -39,3 +39,6 @@
+ #ifdef BUILD_PCAP_MODULE
+ extern const DAQ_Module_t pcap_daq_module_data;
+ #endif
++#ifdef BUILD_SOCKET_MODULE
++extern const DAQ_Module_t socket_daq_module_data;
++#endif
+diff -ruN -x '*.in' -x '*.git*' -x '*m4*' daq-2.0.4-orig/sfbpf/sfbpf_dlt.h daq-2.0.4/sfbpf/sfbpf_dlt.h
+--- daq-2.0.4-orig/sfbpf/sfbpf_dlt.h 2014-06-10 09:38:55.000000000 -0400
++++ daq-2.0.4/sfbpf/sfbpf_dlt.h 2015-05-02 07:39:03.000000000 -0400
+@@ -901,6 +901,9 @@
+ #define DLT_IPV4 228
+ #define DLT_IPV6 229
+
++/* for socket / proxy connections handling payload only */
++#define DLT_SOCKET 230
++
+ /*
+ * DLT and savefile link type values are split into a class and
+ * a member of that class. A class value of 0 indicates a regular
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// cd_socket.cc author Russ Combs <rucombs@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "framework/codec.h"
+#include "../daqs/daq_socket.h"
+#include "protocols/packet.h"
+#include "sfip/sf_ip.h"
+
+#define CD_NAME "socket"
+#define CD_HELP_STR "support for sockets / proxied sessions"
+#define CD_HELP ADD_DLT(CD_HELP_STR, DLT_SOCKET)
+
+class SocketCodec : public Codec
+{
+public:
+ SocketCodec() : Codec(CD_NAME) { };
+ ~SocketCodec() { };
+
+ void get_data_link_type(std::vector<int>& v) override;
+ bool decode(const RawData&, CodecData&, DecodeData&) override;
+};
+
+void SocketCodec::get_data_link_type(std::vector<int>& v)
+{
+ v.push_back(DLT_SOCKET);
+}
+
+static void set_ip(const DAQ_SktHdr_t* pci, CodecData& codec, DecodeData& snort)
+{
+ // FIXIT support ip6
+ sfip_t sip, dip;
+ sfip_set_raw(&sip, &pci->src_addr, AF_INET);
+ sfip_set_raw(&dip, &pci->dst_addr, AF_INET);
+ snort.ip_api.set(sip, dip);
+
+ snort.sp = pci->src_port;
+ snort.dp = pci->dst_port;
+
+ if ( pci->ip_proto == IPPROTO_TCP )
+ codec.proto_bits |= PROTO_BIT__TCP;
+ else
+ codec.proto_bits |= PROTO_BIT__UDP;
+}
+
+static void set_key(CodecData& codec, DecodeData& snort)
+{
+ // FIXIT-L make configurable
+ sfip_t sip, dip;
+ sfip_pton("192.168.1.1", &sip);
+ sfip_pton("192.168.2.2", &dip);
+ snort.ip_api.set(sip, dip);
+
+ snort.sp = 12345;
+ snort.dp = 54321;
+
+ codec.proto_bits |= PROTO_BIT__TCP;
+}
+
+static void set_flags(const DAQ_SktHdr_t* pci, CodecData& codec, DecodeData& snort)
+{
+ if ( pci->flags & DAQ_SKT_FLAG_TO_SERVER )
+ snort.decode_flags |= DECODE_C2S;
+
+ if ( pci->flags & DAQ_SKT_FLAG_START_FLOW )
+ snort.decode_flags |= DECODE_SOF;
+
+ if ( pci->flags & DAQ_SKT_FLAG_END_FLOW )
+ {
+ snort.decode_flags |= DECODE_EOF;
+ codec.lyr_len = 1; // eat pseudo-octet
+ }
+ else
+ codec.lyr_len = 0;
+}
+
+bool SocketCodec::decode(const RawData& raw, CodecData& codec, DecodeData& snort)
+{
+ const DAQ_SktHdr_t* pci = (DAQ_SktHdr_t*)raw.pkth->priv_ptr;
+
+ if ( pci->ip_proto )
+ {
+ set_ip(pci, codec, snort);
+ snort.set_pkt_type(PktType::USER);
+ }
+ else
+ {
+ set_key(codec, snort);
+ snort.set_pkt_type(PktType::FILE);
+ }
+
+ set_flags(pci, codec, snort);
+ return true;
+}
+
+//-------------------------------------------------------------------------
+// api
+//-------------------------------------------------------------------------
+
+static Codec* ctor(Module*)
+{ return new SocketCodec; }
+
+static void dtor(Codec* cd)
+{ delete cd; }
+
+static const CodecApi socket_api =
+{
+ {
+ PT_CODEC,
+ sizeof(CodecApi),
+ CDAPI_VERSION,
+ 0,
+ API_RESERVED,
+ API_OPTIONS,
+ CD_NAME,
+ CD_HELP,
+ nullptr, // mod_ctor
+ nullptr, // mod_dtor
+ },
+ nullptr, // pinit
+ nullptr, // pterm
+ nullptr, // tinit
+ nullptr, // tterm
+ ctor,
+ dtor
+};
+
+SO_PUBLIC const BaseApi* snort_plugins[] =
+{
+ &socket_api.base,
+ nullptr
+};
+
--- /dev/null
+
+
+add_example_library(daq_socket daqs daq_socket.c daq_socket.h)
+add_example_library(daq_file daqs daq_file.c daq_socket.h)
+add_example_library(daq_user daqs daq_user.c daq_socket.h)
+
--- /dev/null
+AUTOMAKE_OPTIONS=foreign
+
+daqlibdir = $(pkglibdir)/daqs
+
+daqlib_LTLIBRARIES = daq_socket.la
+daq_socket_la_CFLAGS = -DBUILDING_SO
+daq_socket_la_LDFLAGS = -module -export-dynamic -avoid-version -shared
+daq_socket_la_SOURCES = daq_socket.c daq_socket.h
+
+daqlib_LTLIBRARIES += daq_file.la
+daq_file_la_CFLAGS = -DBUILDING_SO
+daq_file_la_LDFLAGS = -module -export-dynamic -avoid-version -shared
+daq_file_la_SOURCES = daq_file.c daq_socket.h
+
+daqlib_LTLIBRARIES += daq_user.la
+daq_user_la_CFLAGS = -DBUILDING_SO
+daq_user_la_LDFLAGS = -module -export-dynamic -avoid-version -shared
+daq_user_la_SOURCES = daq_user.c daq_socket.h
+
+AM_CFLAGS = @AM_CFLAGS@
+
--- /dev/null
+/*--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+*/
+/* daq_file.c author Russ Combs <rucombs@cisco.com> */
+
+#include "daq_socket.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/unistd.h>
+
+#include <daq_api.h>
+#include <sfbpf_dlt.h>
+
+#define DAQ_MOD_VERSION 0
+#define DAQ_NAME "file"
+#define DAQ_TYPE (DAQ_TYPE_FILE_CAPABLE|DAQ_TYPE_INTF_CAPABLE|DAQ_TYPE_MULTI_INSTANCE)
+#define FILE_BUF_SZ 16384
+
+typedef struct {
+ char* name;
+ int fid;
+
+ int start;
+ int stop;
+ int eof;
+
+ unsigned snaplen;
+
+ uint8_t* buf;
+ char error[DAQ_ERRBUF_SIZE];
+
+ DAQ_SktHdr_t pci;
+ DAQ_State state;
+ DAQ_Stats_t stats;
+} FileImpl;
+
+//-------------------------------------------------------------------------
+// file functions
+//-------------------------------------------------------------------------
+
+static int file_setup(FileImpl* impl)
+{
+ if ( !strcmp(impl->name, "tty") )
+ {
+ impl->fid = STDIN_FILENO;
+ }
+ else if ( (impl->fid = open(impl->name, O_RDONLY|O_NONBLOCK)) < 0 )
+ {
+ DPE(impl->error, "%s: can't open file (%s)\n",
+ DAQ_NAME, strerror(errno));
+ return -1;
+ }
+ impl->start = 1;
+
+ return 0;
+}
+
+static void file_cleanup(FileImpl* impl)
+{
+ if ( impl->fid > STDIN_FILENO )
+ close(impl->fid);
+
+ impl->fid = -1;
+}
+
+static int file_read(FileImpl* impl)
+{
+ int n = read(impl->fid, impl->buf, impl->snaplen);
+
+ if ( !n )
+ {
+ if ( !impl->eof )
+ {
+ impl->eof = 1;
+ return 1; // <= zero won't make it :(
+ }
+ return DAQ_READFILE_EOF;
+ }
+
+ if ( n < 0 )
+ {
+ if (errno != EINTR)
+ {
+ DPE(impl->error, "%s: can't read from file (%s)\n",
+ DAQ_NAME, strerror(errno));
+ }
+ return DAQ_ERROR;
+ }
+ return n;
+}
+
+//-------------------------------------------------------------------------
+// daq utilities
+//-------------------------------------------------------------------------
+
+static void set_pkt_hdr(FileImpl* impl, DAQ_PktHdr_t* phdr, ssize_t len)
+{
+ struct timeval t;
+ gettimeofday(&t, NULL);
+
+ phdr->ts.tv_sec = t.tv_sec;
+ phdr->ts.tv_usec = t.tv_usec;
+ phdr->caplen = phdr->pktlen = len;
+
+ phdr->ingress_index = phdr->egress_index = -1;
+ phdr->ingress_group = phdr->egress_group = -1;
+
+ phdr->flags = 0;
+ phdr->address_space_id = 0;
+ phdr->opaque = 0;
+
+ if ( impl->start )
+ {
+ impl->pci.flags = DAQ_SKT_FLAG_START_FLOW;
+ impl->start = 0;
+ }
+ else if ( impl->eof )
+ impl->pci.flags = DAQ_SKT_FLAG_END_FLOW;
+
+ else
+ impl->pci.flags = 0;
+
+ phdr->priv_ptr = &impl->pci;
+}
+
+// forward all but drops, retries and blacklists:
+static const int s_fwd[MAX_DAQ_VERDICT] = { 1, 0, 1, 1, 0, 1, 0 };
+
+static int file_daq_process(
+ FileImpl* impl, DAQ_Analysis_Func_t cb, void* user)
+{
+ DAQ_PktHdr_t hdr;
+ int n = file_read(impl);
+
+ if ( n < 1 )
+ return n;
+
+ set_pkt_hdr(impl, &hdr, n);
+ DAQ_Verdict verdict = cb(user, &hdr, impl->buf);
+
+ if ( verdict >= MAX_DAQ_VERDICT )
+ verdict = DAQ_VERDICT_BLOCK;
+
+ impl->stats.verdicts[verdict]++;
+ return n;
+}
+
+//-------------------------------------------------------------------------
+// daq
+//-------------------------------------------------------------------------
+
+static void file_daq_shutdown (void* handle)
+{
+ FileImpl* impl = (FileImpl*)handle;
+
+ if ( impl->name )
+ free(impl->name);
+
+ if ( impl->buf )
+ free(impl->buf);
+
+ free(impl);
+}
+
+//-------------------------------------------------------------------------
+
+static int file_daq_initialize (
+ const DAQ_Config_t* cfg, void** handle, char* errBuf, size_t errMax)
+{
+ FileImpl* impl = calloc(1, sizeof(*impl));
+
+ if ( !impl )
+ {
+ snprintf(errBuf, errMax, "%s: failed to allocate the ipfw context", DAQ_NAME);
+ return DAQ_ERROR_NOMEM;
+ }
+
+ impl->fid = -1;
+ impl->start = impl->stop = 0;
+ impl->snaplen = cfg->snaplen ? cfg->snaplen : FILE_BUF_SZ;
+
+ if ( cfg->name )
+ {
+ if ( !(impl->name = strdup(cfg->name)) )
+ {
+ snprintf(errBuf, errMax, "%s: failed to allocate the filename", DAQ_NAME);
+ return DAQ_ERROR_NOMEM;
+ }
+ }
+
+ if ( !(impl->buf = malloc(impl->snaplen)) )
+ {
+ snprintf(errBuf, errMax, "%s: failed to allocate the ipfw buffer", DAQ_NAME);
+ file_daq_shutdown(impl);
+ return DAQ_ERROR_NOMEM;
+ }
+
+ impl->state = DAQ_STATE_INITIALIZED;
+
+ *handle = impl;
+ return DAQ_SUCCESS;
+}
+
+//-------------------------------------------------------------------------
+
+static int file_daq_start (void* handle)
+{
+ FileImpl* impl = (FileImpl*)handle;
+
+ if ( file_setup(impl) )
+ return DAQ_ERROR;
+
+ impl->state = DAQ_STATE_STARTED;
+ return DAQ_SUCCESS;
+}
+
+static int file_daq_stop (void* handle)
+{
+ FileImpl* impl = (FileImpl*)handle;
+ file_cleanup(impl);
+ impl->state = DAQ_STATE_STOPPED;
+ return DAQ_SUCCESS;
+}
+
+//-------------------------------------------------------------------------
+
+static int file_daq_inject (
+ void* handle, const DAQ_PktHdr_t* hdr, const uint8_t* buf, uint32_t len,
+ int rev)
+{
+ (void)handle;
+ (void)hdr;
+ (void)buf;
+ (void)len;
+ (void)rev;
+ return DAQ_ERROR;
+}
+
+//-------------------------------------------------------------------------
+
+static int file_daq_acquire (
+ void* handle, int cnt, DAQ_Analysis_Func_t callback, DAQ_Meta_Func_t meta, void* user)
+{
+ (void)meta;
+
+ FileImpl* impl = (FileImpl*)handle;
+ int hit = 0, miss = 0;
+ impl->stop = 0;
+
+ while ( hit < cnt || cnt <= 0 )
+ {
+ int status = file_daq_process(impl, callback, user);
+
+ if ( status > 0 )
+ {
+ hit++;
+ miss = 0;
+ }
+ else if ( status < 0 )
+ return status;
+
+ else if ( ++miss == 2 || impl->stop )
+ break;
+ }
+ return DAQ_SUCCESS;
+}
+
+//-------------------------------------------------------------------------
+
+static int file_daq_breakloop (void* handle)
+{
+ FileImpl* impl = (FileImpl*)handle;
+ impl->stop = 1;
+ return DAQ_SUCCESS;
+}
+
+static DAQ_State file_daq_check_status (void* handle)
+{
+ FileImpl* impl = (FileImpl*)handle;
+ return impl->state;
+}
+
+static int file_daq_get_stats (void* handle, DAQ_Stats_t* stats)
+{
+ FileImpl* impl = (FileImpl*)handle;
+ *stats = impl->stats;
+ return DAQ_SUCCESS;
+}
+
+static void file_daq_reset_stats (void* handle)
+{
+ FileImpl* impl = (FileImpl*)handle;
+ memset(&impl->stats, 0, sizeof(impl->stats));
+}
+
+static int file_daq_get_snaplen (void* handle)
+{
+ FileImpl* impl = (FileImpl*)handle;
+ return impl->snaplen;
+}
+
+static uint32_t file_daq_get_capabilities (void* handle)
+{
+ (void)handle;
+ return DAQ_CAPA_BLOCK | DAQ_CAPA_REPLACE | DAQ_CAPA_INJECT | DAQ_CAPA_INJECT_RAW
+ | DAQ_CAPA_BREAKLOOP | DAQ_CAPA_UNPRIV_START;
+}
+
+static int file_daq_get_datalink_type(void *handle)
+{
+ (void)handle;
+ return DLT_SOCKET;
+}
+
+static const char* file_daq_get_errbuf (void* handle)
+{
+ FileImpl* impl = (FileImpl*)handle;
+ return impl->error;
+}
+
+static void file_daq_set_errbuf (void* handle, const char* s)
+{
+ FileImpl* impl = (FileImpl*)handle;
+ DPE(impl->error, "%s", s ? s : "");
+}
+
+static int file_daq_get_device_index(void* handle, const char* device)
+{
+ (void)handle;
+ (void)device;
+ return DAQ_ERROR_NOTSUP;
+}
+
+static int file_daq_set_filter (void* handle, const char* filter)
+{
+ (void)handle;
+ (void)filter;
+ return DAQ_ERROR_NOTSUP;
+}
+
+//-------------------------------------------------------------------------
+
+#ifdef BUILDING_SO
+DAQ_SO_PUBLIC DAQ_Module_t DAQ_MODULE_DATA =
+#else
+DAQ_Module_t file_daq_module_data =
+#endif
+{
+ .api_version = DAQ_API_VERSION,
+ .module_version = DAQ_MOD_VERSION,
+ .name = DAQ_NAME,
+ .type = DAQ_TYPE,
+ .initialize = file_daq_initialize,
+ .set_filter = file_daq_set_filter,
+ .start = file_daq_start,
+ .acquire = file_daq_acquire,
+ .inject = file_daq_inject,
+ .breakloop = file_daq_breakloop,
+ .stop = file_daq_stop,
+ .shutdown = file_daq_shutdown,
+ .check_status = file_daq_check_status,
+ .get_stats = file_daq_get_stats,
+ .reset_stats = file_daq_reset_stats,
+ .get_snaplen = file_daq_get_snaplen,
+ .get_capabilities = file_daq_get_capabilities,
+ .get_datalink_type = file_daq_get_datalink_type,
+ .get_errbuf = file_daq_get_errbuf,
+ .set_errbuf = file_daq_set_errbuf,
+ .get_device_index = file_daq_get_device_index,
+ .modify_flow = NULL,
+ .hup_prep = NULL,
+ .hup_apply = NULL,
+ .hup_post = NULL,
+};
+
--- /dev/null
+/*--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+*/
+/* daq_socket.c author Russ Combs <rucombs@cisco.com> */
+
+#include "daq_socket.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/unistd.h>
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#include <daq_api.h>
+#include <sfbpf_dlt.h>
+
+#define DAQ_MOD_VERSION 0
+#define DAQ_NAME "socket"
+#define DAQ_TYPE (DAQ_TYPE_INTF_CAPABLE | DAQ_TYPE_INLINE_CAPABLE | DAQ_TYPE_MULTI_INSTANCE)
+#define DEFAULT_PORT 8000
+
+typedef struct {
+ int sock_a; // recv from b
+ int sock_b; // recv from a
+ int sock_c; // connect
+
+ int use_a;
+ int port;
+ int passive;
+ int stop;
+
+ unsigned timeout;
+ unsigned snaplen;
+
+ struct sockaddr_in sin_a;
+ struct sockaddr_in sin_b;
+
+ DAQ_SktHdr_t pci;
+
+ uint8_t* buf;
+ char error[DAQ_ERRBUF_SIZE];
+
+ DAQ_State state;
+ DAQ_Stats_t stats;
+} SockImpl;
+
+//-------------------------------------------------------------------------
+// socket functions
+//-------------------------------------------------------------------------
+
+static int sock_setup(SockImpl* impl)
+{
+ struct sockaddr_in sin;
+
+ if ( (impl->sock_c = socket(PF_INET, SOCK_STREAM, 0)) == -1 )
+ {
+ DPE(impl->error, "%s: can't create listener socket (%s)\n",
+ __FUNCTION__, strerror(errno));
+ return -1;
+ }
+
+ sin.sin_family = PF_INET;
+ sin.sin_addr.s_addr = INADDR_ANY;
+ sin.sin_port = htons(impl->port);
+
+ if ( bind(impl->sock_c, (struct sockaddr*)&sin, sizeof(sin)) == -1 )
+ {
+ DPE(impl->error, "%s: can't bind listener socket (%s)\n",
+ __FUNCTION__, strerror(errno));
+ return -1;
+ }
+
+ if ( listen(impl->sock_c, 2) == -1 )
+ {
+ DPE(impl->error, "%s: can't listen on socket (%s)\n",
+ __FUNCTION__, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+static void sock_cleanup(SockImpl* impl)
+{
+ if ( impl->sock_c >= 0 )
+ close(impl->sock_c);
+
+ if ( impl->sock_a >= 0 )
+ close(impl->sock_a);
+
+ if ( impl->sock_b >= 0 )
+ close(impl->sock_b);
+
+ impl->sock_c = impl->sock_a = impl->sock_b = -1;
+}
+
+static int sock_recv(SockImpl* impl, int* sock, struct sockaddr_in* psin)
+{
+ int n = recv(*sock, impl->buf, impl->snaplen, 0);
+
+ if ( n <= 0 )
+ {
+ if (errno != EINTR)
+ {
+ DPE(impl->error, "%s: can't recv from socket (%s)\n",
+ __FUNCTION__, strerror(errno));
+ *sock = -1;
+ psin->sin_addr.s_addr = 0;
+ psin->sin_port = 0;
+ impl->pci.flags = DAQ_SKT_FLAG_END_FLOW;
+ }
+ return 0;
+ }
+ return n;
+}
+
+static int sock_send(
+ SockImpl* impl, int sock, const uint8_t* buf, uint32_t len)
+{
+ if ( sock < 0 )
+ return 0;
+
+ int n = send(sock, buf, len, 0);
+
+ while ( 0 <= n && (uint32_t)n < len )
+ {
+ buf += n;
+ len -= n;
+ n = send(sock, buf, len, 0);
+ }
+ if ( n == -1 )
+ {
+ DPE(impl->error, "%s: can't send on socket (%s)\n",
+ __FUNCTION__, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+static int sock_accept(SockImpl* impl, int* sock, struct sockaddr_in* psin)
+{
+ const char* banner;
+ socklen_t len = sizeof(*psin);
+ *sock = accept(impl->sock_c, (struct sockaddr*)psin, &len);
+
+ if ( *sock == -1 )
+ {
+ DPE(impl->error, "%s: can't accept incoming connection (%s)\n",
+ __FUNCTION__, strerror(errno));
+ return -1;
+ }
+ banner = impl->use_a ? "client\n" : "server\n";
+ sock_send(impl, *sock, (const uint8_t*)banner, 7);
+
+ impl->pci.flags = DAQ_SKT_FLAG_START_FLOW;
+ return 0;
+}
+
+static int sock_poll(SockImpl* impl, int* sock, struct sockaddr_in* psin)
+{
+ int max_fd;
+ fd_set inputs;
+
+ if ( impl->sock_c < 0 )
+ return 0;
+
+ FD_ZERO(&inputs);
+ FD_SET(impl->sock_c, &inputs);
+ max_fd = impl->sock_c;
+
+ if ( *sock > 0 )
+ {
+ FD_SET(*sock, &inputs);
+
+ if ( *sock > max_fd )
+ max_fd = *sock;
+ }
+
+ struct timeval timeout;
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+
+ if ( !select(max_fd+1, &inputs, NULL, NULL, &timeout) )
+ return 0;
+
+ else if ( *sock >= 0 && FD_ISSET(*sock, &inputs) )
+ return sock_recv(impl, sock, psin);
+
+ else if ( *sock < 0 && FD_ISSET(impl->sock_c, &inputs) )
+ return sock_accept(impl, sock, psin);
+
+ return 0;
+}
+
+//-------------------------------------------------------------------------
+// daq utilities
+//-------------------------------------------------------------------------
+
+static void set_pkt_hdr(SockImpl* impl, DAQ_PktHdr_t* phdr, ssize_t len)
+{
+ struct timeval t;
+ gettimeofday(&t, NULL);
+
+ phdr->ts.tv_sec = t.tv_sec;
+ phdr->ts.tv_usec = t.tv_usec;
+ phdr->caplen = len;
+ phdr->pktlen = len;
+ phdr->ingress_index = -1;
+ phdr->egress_index = -1;
+ phdr->ingress_group = -1;
+ phdr->egress_group = -1;
+ phdr->flags = 0;
+ phdr->address_space_id = 0;
+ phdr->opaque = 0;
+
+ // use_a already toggled
+ if ( impl->use_a )
+ {
+ impl->pci.src_addr = impl->sin_b.sin_addr.s_addr;
+ impl->pci.dst_addr = impl->sin_a.sin_addr.s_addr;
+ impl->pci.src_port = impl->sin_b.sin_port;
+ impl->pci.dst_port = impl->sin_a.sin_port;
+ impl->pci.flags &= ~DAQ_SKT_FLAG_TO_SERVER;
+ }
+ else
+ {
+ impl->pci.src_addr = impl->sin_a.sin_addr.s_addr;
+ impl->pci.dst_addr = impl->sin_b.sin_addr.s_addr;
+ impl->pci.src_port = impl->sin_a.sin_port;
+ impl->pci.dst_port = impl->sin_b.sin_port;
+ impl->pci.flags |= DAQ_SKT_FLAG_TO_SERVER;
+ }
+
+ phdr->priv_ptr = &impl->pci;
+}
+
+// forward all but drops, retries and blacklists:
+static const int s_fwd[MAX_DAQ_VERDICT] = { 1, 0, 1, 1, 0, 1, 0 };
+
+static int socket_daq_process(
+ SockImpl* impl, DAQ_Analysis_Func_t cb, void* user)
+{
+ DAQ_PktHdr_t hdr;
+ int* sock = impl->use_a ? &impl->sock_a : &impl->sock_b;
+ struct sockaddr_in* psin = impl->use_a ? &impl->sin_a : &impl->sin_b;
+ impl->pci.flags = 0;
+
+ int n = sock_poll(impl, sock, psin);
+
+ // don't toggle w/o at least one connection so client is always 1st
+ if ( impl->sock_a > -1 || impl->sock_b > -1 )
+ impl->use_a = !impl->use_a;
+
+ if ( n <= 0 && !impl->pci.flags )
+ return n;
+
+ set_pkt_hdr(impl, &hdr, n);
+ DAQ_Verdict verdict = cb(user, &hdr, impl->buf);
+
+ if ( verdict >= MAX_DAQ_VERDICT )
+ verdict = DAQ_VERDICT_BLOCK;
+
+ impl->stats.verdicts[verdict]++;
+
+ if ( impl->passive || s_fwd[verdict] )
+ {
+ // already toggled use_a, so we get a->b or b->a
+ sock = impl->use_a ? &impl->sock_a : &impl->sock_b;
+ sock_send(impl, *sock, impl->buf, n);
+ }
+ return n;
+}
+
+static int socket_daq_config (
+ SockImpl* impl, const DAQ_Config_t* cfg, char* errBuf, size_t errMax)
+{
+ DAQ_Dict* entry;
+
+ if ( cfg->name )
+ {
+ char* end = NULL;
+ impl->port = (int)strtol(cfg->name, &end, 0);
+ }
+ for ( entry = cfg->values; entry; entry = entry->next)
+ {
+ if ( !entry->value || !*entry->value )
+ {
+ snprintf(errBuf, errMax,
+ "%s: variable needs value (%s)\n", __FUNCTION__, entry->key);
+ return DAQ_ERROR;
+ }
+ else if ( !strcmp(entry->key, "port") )
+ {
+ char* end = entry->value;
+ impl->port = (int)strtol(entry->value, &end, 0);
+
+ if ( *end || impl->port <= 0 || impl->port > 65535 )
+ {
+ snprintf(errBuf, errMax, "%s: bad port (%s)\n",
+ __FUNCTION__, entry->value);
+ return DAQ_ERROR;
+ }
+ }
+ else if ( !strcmp(entry->key, "proto") )
+ {
+ if ( !strcmp(entry->value, "tcp") )
+ impl->pci.ip_proto = IPPROTO_TCP;
+
+ else if ( !strcmp(entry->value, "udp") )
+ impl->pci.ip_proto = IPPROTO_UDP;
+ else
+ {
+ snprintf(errBuf, errMax, "%s: bad proto (%s)\n",
+ __FUNCTION__, entry->value);
+ return DAQ_ERROR;
+ }
+ }
+ else
+ {
+ snprintf(errBuf, errMax,
+ "%s: unsupported variable (%s=%s)\n",
+ __FUNCTION__, entry->key, entry->value);
+ return DAQ_ERROR;
+ }
+ }
+ if ( !impl->pci.ip_proto )
+ impl->pci.ip_proto = IPPROTO_TCP;
+
+ if ( !impl->port )
+ impl->port = DEFAULT_PORT;
+
+ impl->snaplen = cfg->snaplen ? cfg->snaplen : IP_MAXPACKET;
+ impl->timeout = cfg->timeout;
+ impl->passive = ( cfg->mode == DAQ_MODE_PASSIVE );
+
+ return DAQ_SUCCESS;
+}
+
+//-------------------------------------------------------------------------
+// daq
+//-------------------------------------------------------------------------
+
+static void socket_daq_shutdown (void* handle)
+{
+ SockImpl* impl = (SockImpl*)handle;
+
+ if ( impl->buf )
+ free(impl->buf);
+
+ free(impl);
+}
+
+//-------------------------------------------------------------------------
+
+static int socket_daq_initialize (
+ const DAQ_Config_t* cfg, void** handle, char* errBuf, size_t errMax)
+{
+ SockImpl* impl = calloc(1, sizeof(*impl));
+
+ if ( !impl )
+ {
+ snprintf(errBuf, errMax, "%s: failed to allocate the ipfw context!",
+ __FUNCTION__);
+ return DAQ_ERROR_NOMEM;
+ }
+
+ if ( socket_daq_config(impl, cfg, errBuf, errMax) != DAQ_SUCCESS )
+ {
+ socket_daq_shutdown(impl);
+ return DAQ_ERROR;
+ }
+ impl->buf = malloc(impl->snaplen);
+
+ if ( !impl->buf )
+ {
+ snprintf(errBuf, errMax, "%s: failed to allocate the ipfw buffer!",
+ __FUNCTION__);
+ socket_daq_shutdown(impl);
+ return DAQ_ERROR_NOMEM;
+ }
+
+ impl->sock_c = impl->sock_a = impl->sock_b = -1;
+ impl->use_a = 1;
+ impl->state = DAQ_STATE_INITIALIZED;
+
+ *handle = impl;
+ return DAQ_SUCCESS;
+}
+
+//-------------------------------------------------------------------------
+
+static int socket_daq_start (void* handle)
+{
+ SockImpl* impl = (SockImpl*)handle;
+
+ if ( sock_setup(impl) )
+ return DAQ_ERROR;
+
+ impl->state = DAQ_STATE_STARTED;
+ return DAQ_SUCCESS;
+}
+
+static int socket_daq_stop (void* handle)
+{
+ SockImpl* impl = (SockImpl*)handle;
+ sock_cleanup(impl);
+ impl->state = DAQ_STATE_STOPPED;
+ return DAQ_SUCCESS;
+}
+
+//-------------------------------------------------------------------------
+
+static int socket_daq_inject (
+ void* handle, const DAQ_PktHdr_t* hdr, const uint8_t* buf, uint32_t len,
+ int reverse)
+{
+ (void)hdr;
+
+ SockImpl* impl = (SockImpl*)handle;
+ int sock;
+
+ if ( reverse )
+ sock = impl->use_a ? impl->sock_b : impl->sock_a;
+ else
+ sock = impl->use_a ? impl->sock_a : impl->sock_b;
+
+ int status = sock_send(impl, sock, buf, len);
+
+ if ( status )
+ return DAQ_ERROR;
+
+ impl->stats.packets_injected++;
+ return DAQ_SUCCESS;
+}
+
+//-------------------------------------------------------------------------
+
+static int socket_daq_acquire (
+ void* handle, int cnt, DAQ_Analysis_Func_t callback, DAQ_Meta_Func_t meta, void* user)
+{
+ (void)meta;
+
+ SockImpl* impl = (SockImpl*)handle;
+ int hit = 0, miss = 0;
+ impl->stop = 0;
+
+ while ( hit < cnt || cnt <= 0 )
+ {
+ int status = socket_daq_process(impl, callback, user);
+
+ if ( status > 0 )
+ {
+ hit++;
+ miss = 0;
+ }
+ else if ( status < 0 )
+ return DAQ_ERROR;
+
+ else if ( ++miss == 2 || impl->stop )
+ break;
+ }
+ return DAQ_SUCCESS;
+}
+
+//-------------------------------------------------------------------------
+
+static int socket_daq_breakloop (void* handle)
+{
+ SockImpl* impl = (SockImpl*)handle;
+ impl->stop = 1;
+ return DAQ_SUCCESS;
+}
+
+static DAQ_State socket_daq_check_status (void* handle)
+{
+ SockImpl* impl = (SockImpl*)handle;
+ return impl->state;
+}
+
+static int socket_daq_get_stats (void* handle, DAQ_Stats_t* stats)
+{
+ SockImpl* impl = (SockImpl*)handle;
+ *stats = impl->stats;
+ return DAQ_SUCCESS;
+}
+
+static void socket_daq_reset_stats (void* handle)
+{
+ SockImpl* impl = (SockImpl*)handle;
+ memset(&impl->stats, 0, sizeof(impl->stats));
+}
+
+static int socket_daq_get_snaplen (void* handle)
+{
+ SockImpl* impl = (SockImpl*)handle;
+ return impl->snaplen;
+}
+
+static uint32_t socket_daq_get_capabilities (void* handle)
+{
+ (void)handle;
+ return DAQ_CAPA_BLOCK | DAQ_CAPA_REPLACE | DAQ_CAPA_INJECT | DAQ_CAPA_INJECT_RAW
+ | DAQ_CAPA_BREAKLOOP | DAQ_CAPA_UNPRIV_START;
+}
+
+static int socket_daq_get_datalink_type(void *handle)
+{
+ (void)handle;
+ return DLT_SOCKET;
+}
+
+static const char* socket_daq_get_errbuf (void* handle)
+{
+ SockImpl* impl = (SockImpl*)handle;
+ return impl->error;
+}
+
+static void socket_daq_set_errbuf (void* handle, const char* s)
+{
+ SockImpl* impl = (SockImpl*)handle;
+ DPE(impl->error, "%s", s ? s : "");
+}
+
+static int socket_daq_get_device_index(void* handle, const char* device)
+{
+ (void)handle;
+ (void)device;
+ return DAQ_ERROR_NOTSUP;
+}
+
+static int socket_daq_set_filter (void* handle, const char* filter)
+{
+ (void)handle;
+ (void)filter;
+ return DAQ_ERROR_NOTSUP;
+}
+
+//-------------------------------------------------------------------------
+
+#ifdef BUILDING_SO
+DAQ_SO_PUBLIC DAQ_Module_t DAQ_MODULE_DATA =
+#else
+DAQ_Module_t socket_daq_module_data =
+#endif
+{
+ .api_version = DAQ_API_VERSION,
+ .module_version = DAQ_MOD_VERSION,
+ .name = DAQ_NAME,
+ .type = DAQ_TYPE,
+ .initialize = socket_daq_initialize,
+ .set_filter = socket_daq_set_filter,
+ .start = socket_daq_start,
+ .acquire = socket_daq_acquire,
+ .inject = socket_daq_inject,
+ .breakloop = socket_daq_breakloop,
+ .stop = socket_daq_stop,
+ .shutdown = socket_daq_shutdown,
+ .check_status = socket_daq_check_status,
+ .get_stats = socket_daq_get_stats,
+ .reset_stats = socket_daq_reset_stats,
+ .get_snaplen = socket_daq_get_snaplen,
+ .get_capabilities = socket_daq_get_capabilities,
+ .get_datalink_type = socket_daq_get_datalink_type,
+ .get_errbuf = socket_daq_get_errbuf,
+ .set_errbuf = socket_daq_set_errbuf,
+ .get_device_index = socket_daq_get_device_index,
+ .modify_flow = NULL,
+ .hup_prep = NULL,
+ .hup_apply = NULL,
+ .hup_post = NULL,
+};
+
--- /dev/null
+/*--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+*/
+/* daq_socket.h author Russ Combs <rucombs@cisco.com> */
+/* this is a C include, not C++ */
+
+#ifndef DAQ_AUX_H
+#define DAQ_AUX_H
+
+#include <stdint.h>
+
+/* for socket / proxy connections handling payload only */
+#define DLT_SOCKET 230
+
+#define DAQ_SKT_FLAG_TO_SERVER 0x01
+#define DAQ_SKT_FLAG_START_FLOW 0x02
+#define DAQ_SKT_FLAG_END_FLOW 0x04
+
+/* socket DAQ sets priv_ptr to this */
+typedef struct
+{
+ uint32_t src_addr;
+ uint32_t dst_addr;
+ uint16_t src_port;
+ uint16_t dst_port;
+ uint8_t ip_proto;
+ uint8_t flags;
+} DAQ_SktHdr_t;
+
+#endif
+
--- /dev/null
+/*--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+*/
+/* daq_user.c author Russ Combs <rucombs@cisco.com> */
+
+#include "daq_socket.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/unistd.h>
+
+#include <daq_api.h>
+#include <sfbpf_dlt.h>
+
+#define DAQ_MOD_VERSION 0
+#define DAQ_NAME "user"
+#define DAQ_TYPE (DAQ_TYPE_FILE_CAPABLE|DAQ_TYPE_INTF_CAPABLE|DAQ_TYPE_MULTI_INSTANCE)
+
+#define DEF_BUF_SZ 16384
+#define MAX_LINE_SZ 128
+
+typedef struct {
+ char* name;
+ FILE* fyle;
+
+ int start;
+ int stop;
+ int eof;
+ int fsm;
+
+ unsigned snaplen;
+ unsigned idx;
+
+ uint8_t* buf;
+ char line[MAX_LINE_SZ];
+ char error[DAQ_ERRBUF_SIZE];
+
+ DAQ_SktHdr_t pci;
+ DAQ_SktHdr_t cfg;
+
+ DAQ_State state;
+ DAQ_Stats_t stats;
+} FileImpl;
+
+//-------------------------------------------------------------------------
+// utility functions
+//-------------------------------------------------------------------------
+
+static void set_c2s(FileImpl* impl, int c2s)
+{
+ if ( c2s )
+ {
+ impl->pci = impl->cfg;
+ }
+ else
+ {
+ impl->pci.src_addr = impl->cfg.dst_addr;
+ impl->pci.dst_addr = impl->cfg.src_addr;
+ impl->pci.src_port = impl->cfg.dst_port;
+ impl->pci.dst_port = impl->cfg.src_port;
+ impl->pci.flags &= ~DAQ_SKT_FLAG_TO_SERVER;
+ }
+}
+
+static void parse_host(const char* s, uint32_t* addr, uint16_t* port)
+{
+ char buf[32]; // oversize so pton() errors out if too long
+ unsigned c = 0;
+
+ while ( isspace(*s) )
+ s++;
+
+ while ( *s && !isspace(*s) && c < sizeof(buf) )
+ buf[c++] = *s++;
+
+ if ( c == sizeof(buf) )
+ --c;
+
+ buf[c] = '\0';
+
+ inet_pton(AF_INET, buf, addr);
+ *port = atoi(s);
+}
+
+static void parse_pci(FileImpl* impl, const char* s)
+{
+ parse_host(s, &impl->pci.src_addr, &impl->pci.src_port);
+
+ s = strstr(s, "->");
+
+ if ( !s )
+ return;
+
+ parse_host(s+2, &impl->pci.dst_addr, &impl->pci.dst_port);
+
+ // hack until client / server is resolved:
+ if ( impl->pci.src_port <= impl->pci.dst_port )
+ impl->pci.flags |= DAQ_SKT_FLAG_TO_SERVER;
+ else
+ impl->pci.flags &= ~DAQ_SKT_FLAG_TO_SERVER;
+}
+
+static unsigned flush(FileImpl* impl)
+{
+ unsigned n = impl->idx;
+ impl->idx = 0;
+ return n;
+}
+
+static uint8_t xlat(char c)
+{
+ switch ( c )
+ {
+ case 'r': return '\r';
+ case 'n': return '\n';
+ case 't': return '\t';
+ case '\\': return '\\';
+ }
+ return c;
+}
+
+static int unescape(char c, char* u)
+{
+ static int esc = 0;
+ if ( !esc && c == '\\' )
+ {
+ esc = 1;
+ return 0;
+ }
+ else if ( esc )
+ {
+ esc = 0;
+ *u = xlat(c);
+ }
+ else
+ *u = c;
+
+ return 1;
+}
+
+//-------------------------------------------------------------------------
+// parsing functions
+//-------------------------------------------------------------------------
+// all commands start with $
+// $packet <addr> <port> -> <addr> <port>
+// $packet -> client
+// $packet -> server
+// $client <addr> <port>
+// $server <addr> <port>
+static void parse_command(FileImpl* impl, char* s)
+{
+ if ( !strncmp(s, "packet -> client", 16) )
+ set_c2s(impl, 0);
+
+ else if ( !strncmp(s, "packet -> server", 16) )
+ set_c2s(impl, 1);
+
+ else if ( !strncmp(s, "packet ", 7) )
+ parse_pci(impl, s+7);
+
+ else if ( !strncmp(s, "client ", 7) )
+ parse_host(s+7, &impl->cfg.src_addr, &impl->cfg.src_port);
+
+ else if ( !strncmp(s, "server ", 7) )
+ parse_host(s+7, &impl->cfg.dst_addr, &impl->cfg.dst_port);
+}
+
+// load quoted string data into buffer up to snaplen
+static void parse_string(FileImpl* impl, char* s)
+{
+ char t;
+
+ while ( *s && *s != '"' && impl->idx < impl->snaplen )
+ {
+ if ( unescape(*s++, &t) )
+ impl->buf[impl->idx++] = t;
+ }
+}
+
+// load hex data into buffer up to snaplen
+static void parse_hex(FileImpl* impl, char* s)
+{
+ char* t = s;
+ long x = strtol(t, &s, 16);
+
+ while ( *s && s != t && impl->idx < impl->snaplen )
+ {
+ impl->buf[impl->idx++] = (uint8_t)x;
+ x = strtol(t=s, &s, 16);
+ }
+}
+
+static int parse(FileImpl* impl)
+{
+ char* s = impl->line;
+
+ while ( isspace(*s) )
+ s++;
+
+ switch ( *s )
+ {
+ case '\0':
+ impl->line[0] = '\0';
+ return flush(impl);
+
+ case '#':
+ break;
+
+ case '$':
+ if ( impl->idx )
+ return flush(impl);
+
+ parse_command(impl, s+1);
+ break;
+
+ case '"':
+ parse_string(impl, s+1);
+ break;
+
+ case 'x':
+ parse_hex(impl, s+1);
+ break;
+ }
+ impl->line[0] = '\0';
+ return 0;
+}
+
+//-------------------------------------------------------------------------
+// file functions
+//-------------------------------------------------------------------------
+
+static int user_setup(FileImpl* impl)
+{
+ if ( !strcmp(impl->name, "tty") )
+ {
+ impl->fyle = stdin;
+ }
+ else if ( !(impl->fyle = fopen(impl->name, "r")) )
+ {
+ DPE(impl->error, "%s: can't open file (%s)\n",
+ DAQ_NAME, strerror(errno));
+ return -1;
+ }
+ parse_host("192.168.1.1 12345", &impl->cfg.src_addr, &impl->cfg.src_port);
+ parse_host("10.1.2.3 80", &impl->cfg.dst_addr, &impl->cfg.dst_port);
+
+ impl->cfg.ip_proto = impl->pci.ip_proto = IPPROTO_TCP;
+ impl->cfg.flags = impl->pci.flags = DAQ_SKT_FLAG_TO_SERVER;
+ impl->start = 1;
+
+ return 0;
+}
+
+static void user_cleanup(FileImpl* impl)
+{
+ if ( impl->fyle != stdin )
+ fclose(impl->fyle);
+
+ impl->fyle = NULL;
+}
+
+static int user_read(FileImpl* impl)
+{
+ int n = 0;
+
+ while ( impl->line[0] || fgets(impl->line, sizeof(impl->line), impl->fyle) )
+ {
+ if ( (n = parse(impl)) )
+ break;
+ }
+
+ if ( !n )
+ n = flush(impl);
+
+ if ( !n )
+ {
+ if ( !impl->eof )
+ {
+ impl->eof = 1;
+ return 1; // <= zero won't make it :(
+ }
+ return DAQ_READFILE_EOF;
+ }
+
+ if ( n < 0 )
+ {
+ if (errno != EINTR)
+ {
+ DPE(impl->error, "%s: can't read from file (%s)\n",
+ DAQ_NAME, strerror(errno));
+ }
+ return DAQ_ERROR;
+ }
+ return n;
+}
+
+//-------------------------------------------------------------------------
+// daq utilities
+//-------------------------------------------------------------------------
+
+static void set_pkt_hdr(FileImpl* impl, DAQ_PktHdr_t* phdr, ssize_t len)
+{
+ struct timeval t;
+ gettimeofday(&t, NULL);
+
+ phdr->ts.tv_sec = t.tv_sec;
+ phdr->ts.tv_usec = t.tv_usec;
+ phdr->caplen = phdr->pktlen = len;
+
+ phdr->ingress_index = phdr->egress_index = -1;
+ phdr->ingress_group = phdr->egress_group = -1;
+
+ phdr->flags = 0;
+ phdr->address_space_id = 0;
+ phdr->opaque = 0;
+
+ impl->pci.flags &= ~(DAQ_SKT_FLAG_START_FLOW|DAQ_SKT_FLAG_END_FLOW);
+
+ if ( impl->start )
+ {
+ impl->pci.flags |= DAQ_SKT_FLAG_START_FLOW;
+ impl->start = 0;
+ }
+ else if ( impl->eof )
+ impl->pci.flags |= DAQ_SKT_FLAG_END_FLOW;
+
+ phdr->priv_ptr = &impl->pci;
+}
+
+// forward all but drops, retries and blacklists:
+static const int s_fwd[MAX_DAQ_VERDICT] = { 1, 0, 1, 1, 0, 1, 0 };
+
+static int user_daq_process(
+ FileImpl* impl, DAQ_Analysis_Func_t cb, void* user)
+{
+ DAQ_PktHdr_t hdr;
+ int n = user_read(impl);
+
+ if ( n < 1 )
+ return n;
+
+ set_pkt_hdr(impl, &hdr, n);
+ DAQ_Verdict verdict = cb(user, &hdr, impl->buf);
+
+ if ( verdict >= MAX_DAQ_VERDICT )
+ verdict = DAQ_VERDICT_BLOCK;
+
+ impl->stats.verdicts[verdict]++;
+ return n;
+}
+
+//-------------------------------------------------------------------------
+// daq
+//-------------------------------------------------------------------------
+
+static void user_daq_shutdown (void* handle)
+{
+ FileImpl* impl = (FileImpl*)handle;
+
+ if ( impl->name )
+ free(impl->name);
+
+ if ( impl->buf )
+ free(impl->buf);
+
+ free(impl);
+}
+
+//-------------------------------------------------------------------------
+
+static int user_daq_initialize (
+ const DAQ_Config_t* cfg, void** handle, char* errBuf, size_t errMax)
+{
+ FileImpl* impl = calloc(1, sizeof(*impl));
+
+ if ( !impl )
+ {
+ snprintf(errBuf, errMax, "%s: failed to allocate the ipfw context", DAQ_NAME);
+ return DAQ_ERROR_NOMEM;
+ }
+
+ impl->fyle = NULL;
+ impl->start = impl->stop = 0;
+ impl->snaplen = cfg->snaplen ? cfg->snaplen : DEF_BUF_SZ;
+
+ impl->idx = 0;
+ impl->fsm = 0;
+ impl->line[0] = '\0';
+
+ if ( cfg->name )
+ {
+ if ( !(impl->name = strdup(cfg->name)) )
+ {
+ snprintf(errBuf, errMax, "%s: failed to allocate the filename", DAQ_NAME);
+ return DAQ_ERROR_NOMEM;
+ }
+ }
+
+ if ( !(impl->buf = malloc(impl->snaplen)) )
+ {
+ snprintf(errBuf, errMax, "%s: failed to allocate the ipfw buffer", DAQ_NAME);
+ user_daq_shutdown(impl);
+ return DAQ_ERROR_NOMEM;
+ }
+
+ impl->state = DAQ_STATE_INITIALIZED;
+
+ *handle = impl;
+ return DAQ_SUCCESS;
+}
+
+//-------------------------------------------------------------------------
+
+static int user_daq_start (void* handle)
+{
+ FileImpl* impl = (FileImpl*)handle;
+
+ if ( user_setup(impl) )
+ return DAQ_ERROR;
+
+ impl->state = DAQ_STATE_STARTED;
+ return DAQ_SUCCESS;
+}
+
+static int user_daq_stop (void* handle)
+{
+ FileImpl* impl = (FileImpl*)handle;
+ user_cleanup(impl);
+ impl->state = DAQ_STATE_STOPPED;
+ return DAQ_SUCCESS;
+}
+
+//-------------------------------------------------------------------------
+
+static int user_daq_inject (
+ void* handle, const DAQ_PktHdr_t* hdr, const uint8_t* buf, uint32_t len, int rev)
+{
+ (void)handle;
+ (void)hdr;
+ (void)buf;
+ (void)len;
+ (void)rev;
+ return DAQ_ERROR;
+}
+
+//-------------------------------------------------------------------------
+
+static int user_daq_acquire (
+ void* handle, int cnt, DAQ_Analysis_Func_t callback, DAQ_Meta_Func_t meta, void* user)
+{
+ (void)meta;
+
+ FileImpl* impl = (FileImpl*)handle;
+ int hit = 0, miss = 0;
+ impl->stop = 0;
+
+ while ( hit < cnt || cnt <= 0 )
+ {
+ int status = user_daq_process(impl, callback, user);
+
+ if ( status > 0 )
+ {
+ hit++;
+ miss = 0;
+ }
+ else if ( status < 0 )
+ return status;
+
+ else if ( ++miss == 2 || impl->stop )
+ break;
+ }
+ return DAQ_SUCCESS;
+}
+
+//-------------------------------------------------------------------------
+
+static int user_daq_breakloop (void* handle)
+{
+ FileImpl* impl = (FileImpl*)handle;
+ impl->stop = 1;
+ return DAQ_SUCCESS;
+}
+
+static DAQ_State user_daq_check_status (void* handle)
+{
+ FileImpl* impl = (FileImpl*)handle;
+ return impl->state;
+}
+
+static int user_daq_get_stats (void* handle, DAQ_Stats_t* stats)
+{
+ FileImpl* impl = (FileImpl*)handle;
+ *stats = impl->stats;
+ return DAQ_SUCCESS;
+}
+
+static void user_daq_reset_stats (void* handle)
+{
+ FileImpl* impl = (FileImpl*)handle;
+ memset(&impl->stats, 0, sizeof(impl->stats));
+}
+
+static int user_daq_get_snaplen (void* handle)
+{
+ FileImpl* impl = (FileImpl*)handle;
+ return impl->snaplen;
+}
+
+static uint32_t user_daq_get_capabilities (void* handle)
+{
+ (void)handle;
+ return DAQ_CAPA_BLOCK | DAQ_CAPA_REPLACE | DAQ_CAPA_INJECT | DAQ_CAPA_INJECT_RAW
+ | DAQ_CAPA_BREAKLOOP | DAQ_CAPA_UNPRIV_START;
+}
+
+static int user_daq_get_datalink_type(void *handle)
+{
+ (void)handle;
+ return DLT_SOCKET;
+}
+
+static const char* user_daq_get_errbuf (void* handle)
+{
+ FileImpl* impl = (FileImpl*)handle;
+ return impl->error;
+}
+
+static void user_daq_set_errbuf (void* handle, const char* s)
+{
+ FileImpl* impl = (FileImpl*)handle;
+ DPE(impl->error, "%s", s ? s : "");
+}
+
+static int user_daq_get_device_index(void* handle, const char* device)
+{
+ (void)handle;
+ (void)device;
+ return DAQ_ERROR_NOTSUP;
+}
+
+static int user_daq_set_filter (void* handle, const char* filter)
+{
+ (void)handle;
+ (void)filter;
+ return DAQ_ERROR_NOTSUP;
+}
+
+//-------------------------------------------------------------------------
+
+#ifdef BUILDING_SO
+DAQ_SO_PUBLIC DAQ_Module_t DAQ_MODULE_DATA =
+#else
+DAQ_Module_t user_daq_module_data =
+#endif
+{
+ .api_version = DAQ_API_VERSION,
+ .module_version = DAQ_MOD_VERSION,
+ .name = DAQ_NAME,
+ .type = DAQ_TYPE,
+ .initialize = user_daq_initialize,
+ .set_filter = user_daq_set_filter,
+ .start = user_daq_start,
+ .acquire = user_daq_acquire,
+ .inject = user_daq_inject,
+ .breakloop = user_daq_breakloop,
+ .stop = user_daq_stop,
+ .shutdown = user_daq_shutdown,
+ .check_status = user_daq_check_status,
+ .get_stats = user_daq_get_stats,
+ .reset_stats = user_daq_reset_stats,
+ .get_snaplen = user_daq_get_snaplen,
+ .get_capabilities = user_daq_get_capabilities,
+ .get_datalink_type = user_daq_get_datalink_type,
+ .get_errbuf = user_daq_get_errbuf,
+ .set_errbuf = user_daq_set_errbuf,
+ .get_device_index = user_daq_get_device_index,
+ .modify_flow = NULL,
+ .hup_prep = NULL,
+ .hup_apply = NULL,
+ .hup_post = NULL,
+};
+
static void dl_tinit()
{
- std::string fname;
- get_instance_file(fname, f_name);
- tlog = TextLog_Init(fname.c_str(), 64*K_BYTES, 1*M_BYTES);
+ tlog = TextLog_Init(f_name, 64*K_BYTES, 1*M_BYTES);
}
static void dl_tterm()
add_example_library(alert_ex loggers alert_ex.cc)
+add_example_library(log_user loggers log_user.cc)
install (
FILES alert.lua
AUTOMAKE_OPTIONS=foreign
loglibdir = $(pkglibdir)/loggers
+
loglib_LTLIBRARIES = libalert_ex.la
libalert_ex_la_CXXFLAGS = $(AM_CXXFLAGS)
libalert_ex_la_LDFLAGS = -export-dynamic -shared
libalert_ex_la_SOURCES = alert_ex.cc
+loglib_LTLIBRARIES += liblog_user.la
+liblog_user_la_CXXFLAGS = $(AM_CXXFLAGS)
+liblog_user_la_LDFLAGS = -export-dynamic -shared
+liblog_user_la_SOURCES = log_user.cc
+
dist_loglib_SCRIPTS = alert.lua
AM_CXXFLAGS = @AM_CXXFLAGS@
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// log_user.cc author Russ Combs <rucombs@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <ctype.h>
+#include <string.h>
+
+#include <algorithm>
+#include <iostream>
+using namespace std;
+
+#include "main/snort_types.h"
+#include "framework/logger.h"
+#include "framework/module.h"
+#include "protocols/packet.h"
+#include "log/text_log.h"
+#include "sfip/sf_ip.h"
+
+#define S_NAME "log_user"
+#define F_NAME S_NAME ".txt"
+
+static const char* s_help = "output payload suitable for daq user";
+
+static THREAD_LOCAL TextLog* user_log = nullptr;
+
+//-------------------------------------------------------------------------
+// impl stuff
+//-------------------------------------------------------------------------
+
+#define LOG_CHARS 20
+
+static void log_header(const Packet* p)
+{
+ char src[INET6_ADDRSTRLEN];
+ char dst[INET6_ADDRSTRLEN];
+
+ const sfip_t* addr = p->ptrs.ip_api.get_src();
+ sfip_ntop(addr, src, sizeof(src));
+
+ addr = p->ptrs.ip_api.get_dst();
+ sfip_ntop(addr, dst, sizeof(dst));
+
+ TextLog_Print(user_log, "\n$packet %s %d -> %s %d\n",
+ src, p->ptrs.sp, dst, p->ptrs.dp);
+}
+
+static void log_data(const uint8_t* p, unsigned n)
+{
+ char hex[(3*LOG_CHARS)+1];
+ char txt[LOG_CHARS+1];
+ unsigned odx = 0, idx = 0;
+
+ TextLog_NewLine(user_log);
+
+ for ( idx = 0; idx < n; idx++)
+ {
+ uint8_t byte = p[idx];
+ sprintf(hex + 3*odx, "%2.02X ", byte);
+ txt[odx++] = isprint(byte) ? byte : '.';
+
+ if ( odx == LOG_CHARS )
+ {
+ txt[odx] = hex[3*odx] = '\0';
+ TextLog_Print(user_log, "x%s # %s\n", hex, txt);
+ odx = 0;
+ }
+ }
+ if ( odx )
+ {
+ txt[odx] = hex[3*odx] = '\0';
+ TextLog_Print(user_log, "x%s", hex);
+
+ while ( odx++ < LOG_CHARS )
+ TextLog_Print(user_log, " ");
+
+ TextLog_Print(user_log, " # %s\n", txt);
+ }
+}
+
+//-------------------------------------------------------------------------
+// module stuff
+//-------------------------------------------------------------------------
+
+static const Parameter s_params[] =
+{
+ { "file", Parameter::PT_BOOL, nullptr, "false",
+ "output to " F_NAME " instead of stdout" },
+
+ { "limit", Parameter::PT_INT, "0:", "0",
+ "set limit (0 is unlimited)" },
+
+ { "units", Parameter::PT_ENUM, "B | K | M | G", "B",
+ "bytes | KB | MB | GB" },
+
+ { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+class UserModule : public Module
+{
+public:
+ UserModule() : Module(S_NAME, s_help, s_params) { }
+
+ bool set(const char*, Value&, SnortConfig*) override;
+ bool begin(const char*, int, SnortConfig*) override;
+ bool end(const char*, int, SnortConfig*) override;
+
+public:
+ bool file;
+ unsigned long limit;
+ unsigned units;
+};
+
+bool UserModule::set(const char*, Value& v, SnortConfig*)
+{
+ if ( v.is("file") )
+ file = v.get_bool();
+
+ else if ( v.is("limit") )
+ limit = v.get_long();
+
+ else if ( v.is("units") )
+ units = v.get_long();
+
+ else
+ return false;
+
+ return true;
+}
+
+bool UserModule::begin(const char*, int, SnortConfig*)
+{
+ file = false;
+ limit = 0;
+ units = 0;
+ return true;
+}
+
+bool UserModule::end(const char*, int, SnortConfig*)
+{
+ while ( units-- )
+ limit *= 1024;
+
+ return true;
+}
+
+//-------------------------------------------------------------------------
+// logger stuff
+//-------------------------------------------------------------------------
+
+class UserLogger : public Logger
+{
+public:
+ UserLogger(UserModule*);
+
+ void open() override;
+ void close() override;
+
+ void log(Packet*, const char* msg, Event*) override;
+
+private:
+ string file;
+ unsigned long limit;
+};
+
+UserLogger::UserLogger(UserModule* m)
+{
+ file = m->file ? F_NAME : "stdout";
+ limit = m->limit;
+}
+
+void UserLogger::open()
+{
+ const unsigned buf_sz = 65536;
+ user_log = TextLog_Init(file.c_str(), buf_sz, limit);
+}
+
+void UserLogger::close()
+{
+ if ( user_log )
+ TextLog_Term(user_log);
+}
+
+void UserLogger::log(Packet* p, const char*, Event*)
+{
+ if ( p->data and p->dsize )
+ {
+ log_header(p);
+ log_data(p->data, p->dsize);
+ }
+}
+
+//-------------------------------------------------------------------------
+// api stuff
+//-------------------------------------------------------------------------
+
+static Module* mod_ctor()
+{ return new UserModule; }
+
+static void mod_dtor(Module* m)
+{ delete m; }
+
+static Logger* user_ctor(SnortConfig*, Module* mod)
+{
+ return new UserLogger((UserModule*)mod);
+}
+
+static void user_dtor(Logger* p)
+{ delete p; }
+
+static const LogApi user_api =
+{
+ {
+ PT_LOGGER,
+ sizeof(LogApi),
+ LOGAPI_VERSION,
+ 0,
+ API_RESERVED,
+ API_OPTIONS,
+ S_NAME,
+ s_help,
+ mod_ctor,
+ mod_dtor
+ },
+ OUTPUT_TYPE_FLAG__ALERT,
+ user_ctor,
+ user_dtor
+};
+
+SO_PUBLIC const BaseApi* snort_plugins[] =
+{
+ &user_api.base,
+ nullptr
+};
+
URL: www.snort.org
Version: @VERSION@
Libs: -L${libdir} -lcurl @LDFLAGS@ @LIBS@
-Cflags: -I${includedir} @CFLAGS@ @CPPFLAGS@
+Cflags: @CFLAGS@ @CPPFLAGS@
stream_icmp
stream_tcp
stream_udp
+ stream_user
+ stream_file
http_inspect
flow
parser
service_inspectors/libservice_inspectors.a \
$(lib_list) \
network_inspectors/port_scan/libport_scan.a \
+stream/libstream.a \
stream/base/libstream_base.a \
stream/ip/libstream_ip.a \
stream/icmp/libstream_icmp.a \
stream/tcp/libstream_tcp.a \
stream/udp/libstream_udp.a \
-stream/libstream.a \
+stream/user/libstream_user.a \
+stream/file/libstream_file.a \
file_api/libfile_api.a \
file_api/libs/libfile.a \
service_inspectors/http_inspect/libhttp_inspect.a \
//--------------------------------------------------------------------------
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2005-2013 Sourcefire, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
void ReplaceAction::exec(Packet* p)
{
- if ( PacketIsRebuilt(p) )
+ if ( p->is_rebuilt() )
return;
Replace_ModifyPacket(p);
//--------------------------------------------------------------------------
-// Copyright (C) 2002-2013 Sourcefire, Inc.
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2002-2013 Sourcefire, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
//--------------------------------------------------------------------------
-// Copyright (C) 2002-2013 Sourcefire, Inc.
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2002-2013 Sourcefire, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
//--------------------------------------------------------------------------
-// Copyright (C) 2002-2013 Sourcefire, Inc.
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2002-2013 Sourcefire, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
//--------------------------------------------------------------------------
-// Copyright (C) 2002-2013 Sourcefire, Inc.
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2002-2013 Sourcefire, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
//--------------------------------------------------------------------------
-// Copyright (C) 2002-2013 Sourcefire, Inc.
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2002-2013 Sourcefire, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
//--------------------------------------------------------------------------
-// Copyright (C) 2002-2013 Sourcefire, Inc.
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2002-2013 Sourcefire, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
//--------------------------------------------------------------------------
-// Copyright (C) 2002-2013 Sourcefire, Inc.
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2002-2013 Sourcefire, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
//--------------------------------------------------------------------------
-// Copyright (C) 2002-2013 Sourcefire, Inc.
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2002-2013 Sourcefire, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
//--------------------------------------------------------------------------
-// Copyright (C) 2002-2013 Sourcefire, Inc.
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2002-2013 Sourcefire, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
//--------------------------------------------------------------------------
-// Copyright (C) 2002-2013 Sourcefire, Inc.
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2002-2013 Sourcefire, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
//--------------------------------------------------------------------------
-// Copyright (C) 2002-2013 Sourcefire, Inc.
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2002-2013 Sourcefire, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
//--------------------------------------------------------------------------
-// Copyright (C) 2002-2013 Sourcefire, Inc.
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2002-2013 Sourcefire, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
//--------------------------------------------------------------------------
-// Copyright (C) 2002-2013 Sourcefire, Inc.
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2002-2013 Sourcefire, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
//--------------------------------------------------------------------------
-// Copyright (C) 2002-2013 Sourcefire, Inc.
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2002-2013 Sourcefire, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
else(STATIC_CODECS)
add_shared_library(cd_gtp codecs cd_gtp.cc)
- add_shared_library(cd_teredo codecs cd_teredo.cc)
add_shared_library(cd_icmp4_ip codecs cd_icmp4_ip.cc)
add_shared_library(cd_icmp6_ip codecs cd_icmp6_ip.cc)
add_shared_library(cd_llc codecs cd_llc.cc)
+ add_shared_library(cd_teredo codecs cd_teredo.cc)
endif(STATIC_CODECS)
if STATIC_CODECS
libmisc_codecs_a_SOURCES += $(plugin_list)
-
else
-ehlibdir = $(pkglibdir)/codecs
+cdlibdir = $(pkglibdir)/codecs
+cdlib_LTLIBRARIES = libcd_gtp.la
+libcd_gtp_la_CXXFLAGS = $(AM_CXXFLAGS) -DBUILDING_SO
+libcd_gtp_la_LDFLAGS = -export-dynamic -shared
+libcd_gtp_la_SOURCES = cd_gtp.cc
-ehlib_LTLIBRARIES = libcd_icmp4_ip.la
+cdlib_LTLIBRARIES += libcd_icmp4_ip.la
libcd_icmp4_ip_la_CXXFLAGS = $(AM_CXXFLAGS) -DBUILDING_SO
libcd_icmp4_ip_la_LDFLAGS = -export-dynamic -shared
libcd_icmp4_ip_la_SOURCES = cd_icmp4_ip.cc
-ehlib_LTLIBRARIES += libcd_icmp6_ip.la
+cdlib_LTLIBRARIES += libcd_icmp6_ip.la
libcd_icmp6_ip_la_CXXFLAGS = $(AM_CXXFLAGS) -DBUILDING_SO
libcd_icmp6_ip_la_LDFLAGS = -export-dynamic -shared
libcd_icmp6_ip_la_SOURCES = cd_icmp6_ip.cc
-ehlib_LTLIBRARIES += libcd_llc.la
+cdlib_LTLIBRARIES += libcd_llc.la
libcd_llc_la_CXXFLAGS = $(AM_CXXFLAGS) -DBUILDING_SO
libcd_llc_la_LDFLAGS = -export-dynamic -shared
libcd_llc_la_SOURCES = cd_llc.cc
-ehlib_LTLIBRARIES += libcd_gtp.la
-libcd_gtp_la_CXXFLAGS = $(AM_CXXFLAGS) -DBUILDING_SO
-libcd_gtp_la_LDFLAGS = -export-dynamic -shared
-libcd_gtp_la_SOURCES = cd_gtp.cc
-
-ehlib_LTLIBRARIES += libcd_teredo.la
+cdlib_LTLIBRARIES += libcd_teredo.la
libcd_teredo_la_CXXFLAGS = $(AM_CXXFLAGS) -DBUILDING_SO
libcd_teredo_la_LDFLAGS = -export-dynamic -shared
libcd_teredo_la_SOURCES = cd_teredo.cc
-
endif
AM_CXXFLAGS = @AM_CXXFLAGS@
+
//--------------------------------------------------------------------------
-// Copyright (C) 2002-2013 Sourcefire, Inc.
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2002-2013 Sourcefire, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
//--------------------------------------------------------------------------
-// Copyright (C) 2002-2013 Sourcefire, Inc.
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2002-2013 Sourcefire, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
//--------------------------------------------------------------------------
-// Copyright (C) 2002-2013 Sourcefire, Inc.
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2002-2013 Sourcefire, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
//--------------------------------------------------------------------------
-// Copyright (C) 2002-2013 Sourcefire, Inc.
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2002-2013 Sourcefire, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
//--------------------------------------------------------------------------
-// Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
// Copyright (C) 2002-2013 Sourcefire, Inc.
+// Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
case PktType::TCP:
case PktType::UDP:
case PktType::ICMP:
+ case PktType::USER:
+ case PktType::FILE:
{
PROFILE_VARS;
return fpEvalHeaderUdp(p, omd);
case PktType::ICMP:
- DEBUG_WRAP(DebugMessage(DEBUG_DETECT,
- "Detecting on IcmpList\n"); );
return fpEvalHeaderIcmp(p, omd);
+ case PktType::USER:
+ case PktType::FILE:
+ if ( p->proto_bits & PROTO_BIT__TCP )
+ return fpEvalHeaderTcp(p, omd);
+
+ else if ( p->proto_bits & PROTO_BIT__UDP )
+ return fpEvalHeaderUdp(p, omd);
+ else
+ break;
+
/*
** No Match on TCP/UDP, Do IP
*/
default:
return fpEvalHeaderIp(p, -1, omd);
- break;
}
+ return 0;
}
// FIXIT-M delete this - see fpAddIpProtoOnlyRule() for details
//--------------------------------------------------------------------------
-// Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
// Copyright (C) 2002-2013 Sourcefire, Inc.
+// Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
return 0;
}
- if (p == NULL || !p->ptrs.ip_api.is_valid())
+ if(p == NULL || !p->ptrs.ip_api.is_ip())
{
DEBUG_WRAP(DebugMessage(DEBUG_FLOW, "bailing from CheckTagList, p->iph == NULL\n"); );
return 0;
file_mime_config.cc
file_mime_config.h
)
+
+target_link_libraries(file_api file)
+
upload);
typedef void (* Log_file_action_func) (Flow* flow, int action);
-typedef int (* File_process_func)(void* p, uint8_t* file_data, int data_size, FilePosition
- position,
+// FIXIT-L constify file_data et al
+typedef int (* File_process_func)(
+ void* p, uint8_t* file_data, int data_size, FilePosition,
bool upload, bool suspend_block_verdict);
+
typedef int (* Get_file_name_func) (Flow* flow, uint8_t** file_name, uint32_t* name_len);
typedef uint64_t (* Get_file_size_func) (Flow* flow);
typedef bool (* Get_file_direction_func) (Flow* flow);
#include "snort_types.h"
#include "file_api.h"
+#include "libs/file_lib.h"
#include "libs/file_config.h"
#include "file_mime_config.h"
#include "file_resume_block.h"
#include "framework/inspector.h"
#include "detection_util.h"
-#include "service_inspectors/http_inspect/hi_main.h" // FIXIT-M bad dependency; use
- // inspector::get_buf()
-static bool file_type_id_enabled = false; // STATIC
+// FIXIT-M bad dependency; use inspector::get_buf()
+#include "service_inspectors/http_inspect/hi_main.h"
+
+int64_t FileConfig::show_data_depth = DEFAULT_FILE_SHOW_DATA_DEPTH;
+bool FileConfig::trace_type = false;
+bool FileConfig::trace_signature = false;
+bool FileConfig::trace_stream = false;
+
+static bool file_type_id_enabled = false;
static bool file_signature_enabled = false;
static bool file_processing_initiated = false;
static void file_signature_lookup(void* p, bool is_retransmit);
-//static void print_file_stats(int exiting);
-
static inline void finish_signature_lookup(FileContext* context, Flow* flow);
static File_Verdict get_file_verdict(Flow* flow);
static void render_block_verdict(void* ctx, void* p);
return context;
}
-#if defined(DEBUG_MSGS) || defined (REG_TEST)
#define MAX_CONTEXT_INFO_LEN 1024
+
static void printFileContext(FileContext* context)
{
char buf[MAX_CONTEXT_INFO_LEN + 1];
}
}
-#endif
-
static inline void updateFileSize(FileContext* context, int data_size, FilePosition position)
{
context->processed_bytes += data_size;
return 0;
if (position == SNORT_FILE_POSITION_UNKNOWN)
return 0;
-#if defined(DEBUG_MSGS) && !defined (REG_TEST)
- if (DEBUG_FILE & GetDebugLevel())
-#endif
-#if defined(DEBUG_MSGS) || defined (REG_TEST)
- DumpHex(stdout, file_data, data_size);
- DEBUG_WRAP(DebugMessage(DEBUG_FILE, "stream pointer %p\n", pkt->flow); );
-#endif
+
+ if ( FileConfig::trace_stream )
+ {
+ DumpHex(stdout, file_data, data_size);
+ DEBUG_WRAP(DebugMessage(DEBUG_FILE, "stream pointer %p\n", pkt->flow); );
+ }
context = get_file_context(p, position, upload);
if (check_http_partial_content(pkt))
{
file_signature_sha256(context, file_data, data_size, position);
-#if defined(DEBUG_MSGS) || defined (REG_TEST)
- if (
-#if defined(DEBUG_MSGS) && !defined (REG_TEST)
- (DEBUG_FILE & GetDebugLevel()) &&
-#endif
- (context->sha256) )
- {
+ if ( context->sha256 and FileConfig::trace_signature )
file_sha256_print(context->sha256);
- }
-#endif
+
_file_signature_lookup(context, p, false, suspend_block_verdict);
}
updateFileSize(context, data_size, position);
{
/* Attempt to get a previously allocated context. */
FileContext* context = get_file_context(flow);
-
file_name_set(context, file_name, name_size);
-#if defined(DEBUG_MSGS) || defined (REG_TEST)
-#if defined(DEBUG_MSGS) && !defined (REG_TEST)
- if (DEBUG_FILE & GetDebugLevel())
-#endif
- printFileContext(context);
-#endif
+
+ if ( FileConfig::trace_type )
+ printFileContext(context);
}
/* Return 1: file name available,
FilePosition position = SNORT_FILE_POSITION_UNKNOWN;
Packet* p = (Packet*)pkt;
- if (PacketHasFullPDU(p))
+ if (p->is_full_pdu())
position = SNORT_FILE_FULL;
- else if (PacketHasStartOfPDU(p))
+ else if (p->is_pdu_start())
position = SNORT_FILE_START;
else if (p->packet_flags & PKT_PDU_TAIL)
position = SNORT_FILE_END;
return c;
}
-#if 0
-static void print_file_stats(int exiting)
+void print_file_stats()
{
int i;
uint64_t processed_total[2];
- uint64_t verdicts_total;
if (!file_stats.files_total)
return;
- LogMessage("File type stats:\n");
+ uint64_t check_total = 0;
+
+ for (i = 0; i < FILE_ID_MAX; i++)
+ {
+ check_total += file_stats.files_processed[i][0];
+ check_total += file_stats.files_processed[i][1];
+ }
+
+ if ( !check_total )
+ return;
+ LogLabel("type stats:");
LogMessage(" Type Download Upload \n");
processed_total[0] = 0;
processed_total[1] = 0;
+
for (i = 0; i < FILE_ID_MAX; i++)
{
- char* type_name = file_info_from_ID(snort_conf->file_config, i);
+ const char* type_name = file_info_from_ID(snort_conf->file_config, i);
if (type_name &&
(file_stats.files_processed[i][0] || file_stats.files_processed[i][1] ))
{
LogMessage(" Total " FMTu64("-10") " " FMTu64("-10") " \n",
processed_total[0], processed_total[1]);
- LogMessage("\nFile signature stats:\n");
+ check_total = 0;
+
+ for (i = 0; i < FILE_ID_MAX; i++)
+ {
+ check_total += file_stats.signatures_processed[i][0];
+ check_total += file_stats.signatures_processed[i][1];
+ }
+
+ if ( !check_total )
+ return;
+ LogLabel("signature stats:");
LogMessage(" Type Download Upload \n");
processed_total[0] = 0;
processed_total[1] = 0;
for (i = 0; i < FILE_ID_MAX; i++)
{
- char* type_name = file_info_from_ID(snort_conf->file_config, i);
+ const char* type_name = file_info_from_ID(snort_conf->file_config, i);
if (type_name &&
(file_stats.signatures_processed[i][0] || file_stats.signatures_processed[i][1] ))
{
LogMessage(" Total " FMTu64("-10") " " FMTu64("-10") " \n",
processed_total[0], processed_total[1]);
+#if 0
LogMessage("\nFile type verdicts:\n");
- verdicts_total = 0;
+ uint64_t verdicts_total = 0;
for (i = 0; i < FILE_VERDICT_MAX; i++)
{
verdicts_total+=file_stats.verdicts_type[i];
}
}
LogMessage(" %12s: " FMTu64("-10") " \n", "Total",verdicts_total);
+#endif
{
LogMessage("\nFiles processed by protocol IDs:\n");
}
}
}
-
- LogMessage("\nTotal files processed: " FMTu64("-10") " \n", file_stats.files_total);
+ //LogMessage("\nTotal files processed: " FMTu64("-10") " \n", file_stats.files_total);
}
-#endif
-
#define FILE_SIGNATURE_SHA256 1
#define FILE_SIGNATURE_SHA256_STR "(file) malware detected"
-void FileAPIInit(void);
-void close_fileAPI(void);
+void FileAPIInit();
+void close_fileAPI();
+void print_file_stats();
#endif
int64_t file_lookup_timeout = DEFAULT_FILE_LOOKUP_TIMEOUT;
bool block_timeout_lookup = false;
-#if defined(DEBUG_MSGS) || defined (REG_TEST)
- int64_t show_data_depth = DEFAULT_FILE_SHOW_DATA_DEPTH;
-#endif
+ static int64_t show_data_depth;
+
+ static bool trace_type;
+ static bool trace_signature;
+ static bool trace_stream;
private:
FileIdenfifier fileIdentifier;
if (append->type_id)
{
if (start->type_id)
- LogMessage("Duplicated type definition '%d -> %d at offset %d.\n",
+ ParseWarning(WARN_RULES, "Duplicated type definition '%d -> %d at offset %d.\n",
start->type_id, append->type_id, append->offset);
start->type_id = append->type_id;
}
}
/*Main File Processing functions */
-void file_type_id(FileContext* context, uint8_t* file_data, int data_size, FilePosition position)
+void file_type_id(FileContext* context, uint8_t* file_data,
+ int data_size, FilePosition position)
{
FileConfig* file_config = (FileConfig*) context->file_config;
}
}
-void file_signature_sha256(FileContext* context, uint8_t* file_data, int data_size, FilePosition
- position)
+void file_signature_sha256(
+ FileContext* context, uint8_t* file_data, int data_size, FilePosition position)
{
if (!context)
return;
return NULL;
}
-#if defined(DEBUG_MSGS) || defined (REG_TEST)
/*
* Print a 32-byte hash value.
*/
hash[28], hash[29], hash[30], hash[31]);
}
-#endif
-
extern int64_t file_signature_depth;
void free_file_identifiers(void*);
-#if defined(DEBUG_MSGS) || defined (REG_TEST)
void file_sha256_print(unsigned char* hash);
-#endif
+
#endif
const sfip_t* dip;
sfip_t cleared;
- if ( p->ptrs.ip_api.is_valid() )
+ if ( p->ptrs.ip_api.is_ip() )
{
sip = p->ptrs.ip_api.get_src();
dip = p->ptrs.ip_api.get_dst();
sfip_t ip2;
uint16_t port1;
uint16_t port2;
- uint32_t protocol;
+ PktType protocol;
bool set(
- const sfip_t* cliIP, uint16_t cliPort,
- const sfip_t* srvIP, uint16_t srvPort,
- uint8_t proto);
+ const sfip_t *cliIP, uint16_t cliPort,
+ const sfip_t *srvIP, uint16_t srvPort,
+ PktType proto);
};
inline bool ExpectKey::set(
- const sfip_t* cliIP, uint16_t cliPort,
- const sfip_t* srvIP, uint16_t srvPort,
- uint8_t proto)
+ const sfip_t *cliIP, uint16_t cliPort,
+ const sfip_t *srvIP, uint16_t srvPort,
+ PktType proto )
{
bool reverse;
SFIP_RET rval = sfip_compare(cliIP, srvIP);
port2 = cliPort;
reverse = true;
}
- protocol = static_cast<uint32_t>(proto);
+ protocol = proto;
return reverse;
}
* session expiry in seconds.
*/
int ExpectCache::add_flow(
- const sfip_t* cliIP, uint16_t cliPort,
- const sfip_t* srvIP, uint16_t srvPort,
- uint8_t protocol, char direction,
+ const sfip_t *cliIP, uint16_t cliPort,
+ const sfip_t *srvIP, uint16_t srvPort,
+ PktType protocol, char direction,
FlowData* fd, int16_t appId)
{
assert(!cliPort || !srvPort);
const sfip_t* dstIP = p->ptrs.ip_api.get_dst();
ExpectKey key;
- bool reversed_key = key.set(dstIP, p->ptrs.dp, srcIP, p->ptrs.sp, p->get_ip_proto_next());
+ bool reversed_key = key.set(dstIP, p->ptrs.dp, srcIP, p->ptrs.sp, p->type());
uint16_t port1;
uint16_t port2;
~ExpectCache();
int add_flow(
- const sfip_t* cliIP, uint16_t cliPort,
- const sfip_t* srvIP, uint16_t srvPort,
- uint8_t protocol, char direction,
- FlowData*, int16_t appId = 0);
+ const sfip_t *cliIP, uint16_t cliPort,
+ const sfip_t *srvIP, uint16_t srvPort,
+ PktType, char direction, FlowData*, int16_t appId = 0);
bool is_expected(Packet*);
char process_expected(Packet*, Flow*);
* If there are no IP layers, then
* outer_ip.is_valid() == inner_ip.is_valid() == false
*/
- if (outer_ip_api.is_valid())
+ if (outer_ip_api.is_ip())
{
// FIXIT-J!! -- Do we want more than just the outermost
// and innermost ttl()?
#define SSNFLAG_SEEN_SENDER 0x00000001
#define SSNFLAG_SEEN_SERVER 0x00000002
#define SSNFLAG_SEEN_RESPONDER 0x00000002
+
#define SSNFLAG_ESTABLISHED 0x00000004
#define SSNFLAG_MIDSTREAM 0x00000008 /* picked up midstream */
#define SSNFLAG_PROXIED 0x01000000
#define SSNFLAG_NONE 0x00000000 /* nothing, an MT bag of chips */
+#define SSNFLAG_SEEN_BOTH (SSNFLAG_SEEN_SERVER | SSNFLAG_SEEN_CLIENT)
#define SSNFLAG_BLOCK (SSNFLAG_DROP_CLIENT|SSNFLAG_DROP_SERVER)
#define STREAM_STATE_NONE 0x0000
char ignore_direction;
};
-enum Stream_Event
-{
- SE_REXMIT,
- SE_EOF,
- SE_MAX
-};
-
// this struct is organized by member size for compactness
class Flow
{
void set_ttl(Packet*, bool client);
+ bool two_way_traffic()
+ { return (ssn_state.session_flags & SSNFLAG_SEEN_BOTH) == SSNFLAG_SEEN_BOTH; }
+
void set_proxied()
{ ssn_state.session_flags |= SSNFLAG_PROXIED; }
bool is_proxied()
{ return (ssn_state.session_flags & SSNFLAG_PROXIED) != 0; }
+ bool is_stream()
+ { return (unsigned)protocol & (unsigned)PktType::STREAM; }
+
void block()
{ ssn_state.session_flags |= SSNFLAG_BLOCK; }
uint16_t ssn_policy;
uint16_t session_state;
- uint8_t handler[SE_MAX];
- uint8_t response_count;
+ uint8_t inner_client_ttl, inner_server_ttl;
+ uint8_t outer_client_ttl, outer_server_ttl;
- uint8_t inner_client_ttl, inner_server_ttl;
- uint8_t outer_client_ttl, outer_server_ttl;
+ uint8_t response_count;
};
#endif
icmp_cache = nullptr;
tcp_cache = nullptr;
udp_cache = nullptr;
+ user_cache = nullptr;
+ file_cache = nullptr;
exp_cache = nullptr;
+ ip_mem = icmp_mem = nullptr;
tcp_mem = udp_mem = nullptr;
- icmp_mem = ip_mem = nullptr;
+ user_mem = file_mem = nullptr;
+ get_ip = get_icmp = nullptr;
get_tcp = get_udp = nullptr;
- get_icmp = get_ip = nullptr;
+ get_user = get_file = nullptr;
}
FlowControl::~FlowControl()
{
+ delete ip_cache;
+ delete icmp_cache;
delete tcp_cache;
delete udp_cache;
- delete icmp_cache;
- delete ip_cache;
+ delete user_cache;
+ delete file_cache;
delete exp_cache;
+ free(ip_mem);
+ free(icmp_mem);
free(tcp_mem);
free(udp_mem);
- free(icmp_mem);
- free(ip_mem);
+ free(user_mem);
+ free(file_mem);
}
//-------------------------------------------------------------------------
// count foo
//-------------------------------------------------------------------------
+static THREAD_LOCAL PegCount ip_count = 0;
+static THREAD_LOCAL PegCount icmp_count = 0;
static THREAD_LOCAL PegCount tcp_count = 0;
static THREAD_LOCAL PegCount udp_count = 0;
-static THREAD_LOCAL PegCount icmp_count = 0;
-static THREAD_LOCAL PegCount ip_count = 0;
+static THREAD_LOCAL PegCount user_count = 0;
+static THREAD_LOCAL PegCount file_count = 0;
-uint32_t FlowControl::max_flows(uint8_t proto)
+uint32_t FlowControl::max_flows(PktType proto)
{
FlowCache* cache = get_cache(proto);
return 0;
}
-PegCount FlowControl::get_prunes(uint8_t proto)
+PegCount FlowControl::get_prunes (PktType proto)
{
FlowCache* cache = get_cache(proto);
return cache ? cache->get_prunes() : 0;
}
-PegCount FlowControl::get_flows(uint8_t proto)
+PegCount FlowControl::get_flows(PktType proto)
{
switch ( proto )
{
- // FIXIT should be using an enum for these
- case IPPROTO_TCP: return tcp_count;
- case IPPROTO_UDP: return udp_count;
- case IPPROTO_ICMP: return icmp_count;
- case IPPROTO_IP: return ip_count;
+ case PktType::IP: return ip_count;
+ case PktType::ICMP: return icmp_count;
+ case PktType::TCP: return tcp_count;
+ case PktType::UDP: return udp_count;
+ case PktType::USER: return user_count;
+ case PktType::FILE: return file_count;
default: return 0;
}
}
void FlowControl::clear_counts()
{
+ ip_count = icmp_count = 0;
tcp_count = udp_count = 0;
- icmp_count = ip_count = 0;
+ user_count = file_count = 0;
FlowCache* cache;
- if ( (cache = get_cache(IPPROTO_IP)) )
+ if ( (cache = get_cache(PktType::IP)) )
cache->reset_prunes();
- if ( (cache = get_cache(IPPROTO_ICMP)) )
+ if ( (cache = get_cache(PktType::ICMP)) )
cache->reset_prunes();
- if ( (cache = get_cache(IPPROTO_TCP)) )
+ if ( (cache = get_cache(PktType::TCP)) )
cache->reset_prunes();
- if ( (cache = get_cache(IPPROTO_UDP)) )
+ if ( (cache = get_cache(PktType::UDP)) )
+ cache->reset_prunes();
+
+ if ( (cache = get_cache(PktType::USER)) )
+ cache->reset_prunes();
+
+ if ( (cache = get_cache(PktType::FILE)) )
cache->reset_prunes();
}
// cache foo
//-------------------------------------------------------------------------
-inline FlowCache* FlowControl::get_cache(uint8_t proto)
+inline FlowCache* FlowControl::get_cache (PktType proto)
{
switch ( proto )
{
- case IPPROTO_TCP: return tcp_cache;
- case IPPROTO_UDP: return udp_cache;
- case IPPROTO_ICMP: return icmp_cache;
- case IPPROTO_IP: return ip_cache;
- default: return nullptr;
+ case PktType::IP: return ip_cache;
+ case PktType::ICMP: return icmp_cache;
+ case PktType::TCP: return tcp_cache;
+ case PktType::UDP: return udp_cache;
+ case PktType::USER: return user_cache;
+ case PktType::FILE: return file_cache;
+ default: return nullptr;
}
}
Flow* FlowControl::find_flow(const FlowKey* key)
{
- FlowCache* cache = get_cache(key->protocol);
+ FlowCache* cache = get_cache((PktType)key->protocol);
if ( cache )
return cache->find(key);
Flow* FlowControl::new_flow(const FlowKey* key)
{
- FlowCache* cache = get_cache(key->protocol);
+ FlowCache* cache = get_cache((PktType)key->protocol);
if ( !cache )
return NULL;
// protocol are obviated for existing / initialized flows
void FlowControl::delete_flow(const FlowKey* key)
{
- FlowCache* cache = get_cache(key->protocol);
+ FlowCache* cache = get_cache((PktType)key->protocol);
if ( !cache )
return;
void FlowControl::delete_flow(Flow* flow, const char* why)
{
- FlowCache* cache = get_cache(flow->ip_proto);
+ FlowCache* cache = get_cache(flow->protocol);
if ( cache )
cache->release(flow, why);
}
-void FlowControl::purge_flows(uint8_t proto)
+void FlowControl::purge_flows (PktType proto)
{
FlowCache* cache = get_cache(proto);
cache->purge();
}
-void FlowControl::prune_flows(uint8_t proto, Packet* p)
+void FlowControl::prune_flows (PktType proto, Packet* p)
{
FlowCache* cache = get_cache(proto);
{
Active_Suspend();
+ if ( ip_cache )
+ ip_cache->timeout(flowCount, cur_time);
+
+ //if ( icmp_cache )
+ //icmp_cache does not need cleaning
+
if ( tcp_cache )
tcp_cache->timeout(flowCount, cur_time);
if ( udp_cache )
udp_cache->timeout(flowCount, cur_time);
- //if ( icmp_cache )
- //icmp_cache does not need cleaning
+ if ( user_cache )
+ user_cache->timeout(flowCount, cur_time);
- if ( ip_cache )
- ip_cache->timeout(flowCount, cur_time);
+ if ( file_cache )
+ file_cache->timeout(flowCount, cur_time);
Active_Resume();
}
uint32_t mplsId;
uint16_t vlanId;
uint16_t addressSpaceId;
- uint8_t proto = p->get_ip_proto_next();
+ uint8_t type = (uint8_t)p->type();
+ uint8_t proto = (uint8_t)p->get_ip_proto_next();
if ( p->proto_bits & PROTO_BIT__VLAN )
vlanId = layer::get_vlan_layer(p)->vid();
if ( (p->ptrs.decode_flags & DECODE_FRAG) )
{
- key->init(ip_api.get_src(), ip_api.get_dst(), ip_api.id(),
- proto, vlanId, mplsId, addressSpaceId);
+ key->init(type, proto, ip_api.get_src(), ip_api.get_dst(), ip_api.id(),
+ vlanId, mplsId, addressSpaceId);
}
- else if (p->type() == PktType::ICMP)
+ else if ( type == (uint8_t)PktType::ICMP )
{
- key->init(ip_api.get_src(), p->ptrs.icmph->type, ip_api.get_dst(), 0,
- proto, vlanId, mplsId, addressSpaceId);
+ key->init(type, proto, ip_api.get_src(), p->ptrs.icmph->type, ip_api.get_dst(), 0,
+ vlanId, mplsId, addressSpaceId);
}
else
{
- key->init(ip_api.get_src(), p->ptrs.sp, ip_api.get_dst(), p->ptrs.dp,
- proto, vlanId, mplsId, addressSpaceId);
+ key->init(type, proto, ip_api.get_src(), p->ptrs.sp, ip_api.get_dst(), p->ptrs.dp,
+ vlanId, mplsId, addressSpaceId);
}
}
}
// FIXIT-L init_roles* should take const Packet*
+static void init_roles_ip(Packet* p, Flow* flow)
+{
+ flow->ssn_state.direction = FROM_SENDER;
+ sfip_copy(flow->client_ip, p->ptrs.ip_api.get_src());
+ sfip_copy(flow->server_ip, p->ptrs.ip_api.get_dst());
+}
+
static void init_roles_tcp(Packet* p, Flow* flow)
{
if ( p->ptrs.tcph->is_syn_only() )
flow->server_port = ntohs(p->ptrs.udph->uh_dport);
}
-static void init_roles_ip(Packet* p, Flow* flow)
+static void init_roles_user(Packet* p, Flow* flow)
{
- flow->ssn_state.direction = FROM_SENDER;
- sfip_copy(flow->client_ip, p->ptrs.ip_api.get_src());
- sfip_copy(flow->server_ip, p->ptrs.ip_api.get_dst());
+ if ( p->ptrs.decode_flags & DECODE_C2S )
+ {
+ flow->ssn_state.direction = FROM_CLIENT;
+ sfip_copy(flow->client_ip, p->ptrs.ip_api.get_src());
+ flow->client_port = p->ptrs.sp;
+ sfip_copy(flow->server_ip, p->ptrs.ip_api.get_dst());
+ flow->server_port = p->ptrs.dp;
+ }
+ else
+ {
+ flow->ssn_state.direction = FROM_SERVER;
+ sfip_copy(flow->client_ip, p->ptrs.ip_api.get_dst());
+ flow->client_port = p->ptrs.dp;
+ sfip_copy(flow->server_ip, p->ptrs.ip_api.get_src());
+ flow->server_port = p->ptrs.sp;
+ }
}
static void init_roles(Packet* p, Flow* flow)
{
switch ( flow->protocol )
{
+ case PktType::IP:
+ case PktType::ICMP:
+ init_roles_ip(p, flow);
+ break;
+
case PktType::TCP:
init_roles_tcp(p, flow);
break;
init_roles_udp(p, flow);
break;
- case PktType::IP:
- case PktType::ICMP:
- init_roles_ip(p, flow);
+ case PktType::USER:
+ case PktType::FILE:
+ init_roles_user(p, flow);
break;
default:
return news;
}
+//-------------------------------------------------------------------------
+// ip
+//-------------------------------------------------------------------------
+
+void FlowControl::init_ip(
+ const FlowConfig& fc, InspectSsnFunc get_ssn)
+{
+ if ( !fc.max_sessions || !get_ssn )
+ return;
+
+ ip_cache = new FlowCache(
+ fc.max_sessions, fc.cache_pruning_timeout,
+ fc.cache_nominal_timeout, 5, 0);
+
+ ip_mem = (Flow*)calloc(fc.max_sessions, sizeof(Flow));
+
+ if ( !ip_mem )
+ return;
+
+ for ( unsigned i = 0; i < fc.max_sessions; ++i )
+ ip_cache->push(ip_mem + i);
+
+ get_ip = get_ssn;
+}
+
+void FlowControl::process_ip(Packet* p)
+{
+ if ( !ip_cache )
+ return;
+
+ FlowKey key;
+ set_key(&key, p);
+ Flow* flow = ip_cache->get(&key);
+
+ if ( !flow )
+ return;
+
+ if ( !flow->session )
+ {
+ flow->init(PktType::IP);
+ flow->session = get_ip(flow);
+ }
+
+ ip_count += process(flow, p);
+
+ if ( flow->next && is_bidirectional(flow) )
+ ip_cache->unlink_uni(flow);
+}
+
+//-------------------------------------------------------------------------
+// icmp
+//-------------------------------------------------------------------------
+
+void FlowControl::init_icmp(
+ const FlowConfig& fc, InspectSsnFunc get_ssn)
+{
+ if ( !fc.max_sessions || !get_ssn )
+ return;
+
+ icmp_cache = new FlowCache(
+ fc.max_sessions, fc.cache_pruning_timeout,
+ fc.cache_nominal_timeout, 5, 0);
+
+ icmp_mem = (Flow*)calloc(fc.max_sessions, sizeof(Flow));
+
+ if ( !icmp_mem )
+ return;
+
+ for ( unsigned i = 0; i < fc.max_sessions; ++i )
+ icmp_cache->push(icmp_mem + i);
+
+ get_icmp = get_ssn;
+}
+
+void FlowControl::process_icmp(Packet* p)
+{
+ if ( !icmp_cache )
+ {
+ process_ip(p);
+ return;
+ }
+
+ FlowKey key;
+ set_key(&key, p);
+ Flow* flow = icmp_cache->get(&key);
+
+ if ( !flow )
+ return;
+
+ if ( !flow->session )
+ {
+ flow->init(PktType::ICMP);
+ flow->session = get_icmp(flow);
+ }
+
+ icmp_count += process(flow, p);
+
+ if ( flow->next && is_bidirectional(flow) )
+ icmp_cache->unlink_uni(flow);
+}
+
//-------------------------------------------------------------------------
// tcp
//-------------------------------------------------------------------------
}
//-------------------------------------------------------------------------
-// icmp
+// user
//-------------------------------------------------------------------------
-void FlowControl::init_icmp(
+void FlowControl::init_user(
const FlowConfig& fc, InspectSsnFunc get_ssn)
{
if ( !fc.max_sessions || !get_ssn )
return;
- icmp_cache = new FlowCache(
+ user_cache = new FlowCache(
fc.max_sessions, fc.cache_pruning_timeout,
fc.cache_nominal_timeout, 5, 0);
- icmp_mem = (Flow*)calloc(fc.max_sessions, sizeof(Flow));
+ user_mem = (Flow*)calloc(fc.max_sessions, sizeof(Flow));
- if ( !icmp_mem )
+ if ( !user_mem )
return;
for ( unsigned i = 0; i < fc.max_sessions; ++i )
- icmp_cache->push(icmp_mem + i);
+ user_cache->push(user_mem + i);
- get_icmp = get_ssn;
+ get_user = get_ssn;
}
-void FlowControl::process_icmp(Packet* p)
+void FlowControl::process_user(Packet* p)
{
- if ( !icmp_cache )
- {
- process_ip(p);
+ if ( !user_cache )
return;
- }
FlowKey key;
set_key(&key, p);
- Flow* flow = icmp_cache->get(&key);
+ Flow* flow = user_cache->get(&key);
if ( !flow )
return;
if ( !flow->session )
{
- flow->init(PktType::ICMP);
- flow->session = get_icmp(flow);
+ flow->init(PktType::USER);
+ flow->session = get_user(flow);
}
- icmp_count += process(flow, p);
+ user_count += process(flow, p);
if ( flow->next && is_bidirectional(flow) )
- icmp_cache->unlink_uni(flow);
+ user_cache->unlink_uni(flow);
}
//-------------------------------------------------------------------------
-// ip
+// file
//-------------------------------------------------------------------------
-void FlowControl::init_ip(
+void FlowControl::init_file(
const FlowConfig& fc, InspectSsnFunc get_ssn)
{
if ( !fc.max_sessions || !get_ssn )
return;
- ip_cache = new FlowCache(
+ file_cache = new FlowCache(
fc.max_sessions, fc.cache_pruning_timeout,
fc.cache_nominal_timeout, 5, 0);
- ip_mem = (Flow*)calloc(fc.max_sessions, sizeof(Flow));
+ file_mem = (Flow*)calloc(fc.max_sessions, sizeof(Flow));
- if ( !ip_mem )
+ if ( !file_mem )
return;
for ( unsigned i = 0; i < fc.max_sessions; ++i )
- ip_cache->push(ip_mem + i);
+ file_cache->push(file_mem + i);
- get_ip = get_ssn;
+ get_file = get_ssn;
}
-void FlowControl::process_ip(Packet* p)
+void FlowControl::process_file(Packet* p)
{
- if ( !ip_cache )
+ if ( !file_cache )
return;
FlowKey key;
set_key(&key, p);
- Flow* flow = ip_cache->get(&key);
+ Flow* flow = file_cache->get(&key);
if ( !flow )
return;
if ( !flow->session )
{
- flow->init(PktType::IP);
- flow->session = get_ip(flow);
+ flow->init(PktType::FILE);
+ flow->session = get_file(flow);
}
- ip_count += process(flow, p);
-
- if ( flow->next && is_bidirectional(flow) )
- ip_cache->unlink_uni(flow);
+ file_count += process(flow, p);
}
//-------------------------------------------------------------------------
// expected
//-------------------------------------------------------------------------
-void FlowControl::init_exp(
- const FlowConfig& tcp, const FlowConfig& udp)
+void FlowControl::init_exp(uint32_t max)
{
- uint32_t max = tcp.max_sessions + udp.max_sessions;
max >>= 9;
if ( !max )
}
int FlowControl::add_expected(
- const sfip_t* srcIP, uint16_t srcPort,
- const sfip_t* dstIP, uint16_t dstPort,
- uint8_t protocol, char direction,
+ const sfip_t *srcIP, uint16_t srcPort,
+ const sfip_t *dstIP, uint16_t dstPort,
+ PktType protocol, char direction,
FlowData* fd)
{
return exp_cache->add_flow(
}
int FlowControl::add_expected(
- const sfip_t* srcIP, uint16_t srcPort,
- const sfip_t* dstIP, uint16_t dstPort,
- uint8_t protocol, int16_t appId, FlowData* fd)
+ const sfip_t *srcIP, uint16_t srcPort,
+ const sfip_t *dstIP, uint16_t dstPort,
+ PktType protocol, int16_t appId, FlowData* fd)
{
return exp_cache->add_flow(
srcIP, srcPort, dstIP, dstPort, protocol, SSN_DIR_BOTH, fd, appId);
void process_icmp(Packet*);
void process_tcp(Packet*);
void process_udp(Packet*);
+ void process_user(Packet*);
+ void process_file(Packet*);
Flow* find_flow(const FlowKey*);
Flow* new_flow(const FlowKey*);
- void init_tcp(const FlowConfig &, InspectSsnFunc);
- void init_udp(const FlowConfig &, InspectSsnFunc);
- void init_icmp(const FlowConfig &, InspectSsnFunc);
- void init_ip(const FlowConfig &, InspectSsnFunc);
- void init_exp(const FlowConfig& tcp, const FlowConfig& udp);
+ void init_ip(const FlowConfig&, InspectSsnFunc);
+ void init_icmp(const FlowConfig&, InspectSsnFunc);
+ void init_tcp(const FlowConfig&, InspectSsnFunc);
+ void init_udp(const FlowConfig&, InspectSsnFunc);
+ void init_user(const FlowConfig&, InspectSsnFunc);
+ void init_file(const FlowConfig&, InspectSsnFunc);
+ void init_exp(uint32_t max);
void delete_flow(const FlowKey*);
void delete_flow(Flow*, const char* why);
- void purge_flows(uint8_t proto);
- void prune_flows(uint8_t proto, Packet*);
+ void purge_flows(PktType);
+ void prune_flows(PktType, Packet*);
void timeout_flows(uint32_t flowCount, time_t cur_time);
char expected_flow(Flow*, Packet*);
bool is_expected(Packet*);
int add_expected(
- const sfip_t* srcIP, uint16_t srcPort,
- const sfip_t* dstIP, uint16_t dstPort,
- uint8_t protocol, char direction, FlowData*);
+ const sfip_t *srcIP, uint16_t srcPort,
+ const sfip_t *dstIP, uint16_t dstPort,
+ PktType, char direction, FlowData*);
int add_expected(
- const sfip_t* srcIP, uint16_t srcPort,
- const sfip_t* dstIP, uint16_t dstPort,
- uint8_t protocol, int16_t appId, FlowData*);
+ const sfip_t *srcIP, uint16_t srcPort,
+ const sfip_t *dstIP, uint16_t dstPort,
+ PktType, int16_t appId, FlowData*);
- uint32_t max_flows(uint8_t proto);
+ uint32_t max_flows(PktType);
- PegCount get_prunes(uint8_t);
- PegCount get_flows(uint8_t);
+ PegCount get_prunes(PktType);
+ PegCount get_flows(PktType);
void clear_counts();
private:
- class FlowCache* get_cache(uint8_t);
+ class FlowCache* get_cache(PktType);
void set_key(FlowKey*, Packet*);
unsigned process(Flow*, Packet*);
private:
+ FlowCache* ip_cache;
+ FlowCache* icmp_cache;
FlowCache* tcp_cache;
FlowCache* udp_cache;
- FlowCache* icmp_cache;
- FlowCache* ip_cache;
+ FlowCache* user_cache;
+ FlowCache* file_cache;
+ Flow* ip_mem;
+ Flow* icmp_mem;
Flow* tcp_mem;
Flow* udp_mem;
- Flow* icmp_mem;
- Flow* ip_mem;
+ Flow* user_mem;
+ Flow* file_mem;
+ InspectSsnFunc get_ip;
+ InspectSsnFunc get_icmp;
InspectSsnFunc get_tcp;
InspectSsnFunc get_udp;
- InspectSsnFunc get_icmp;
- InspectSsnFunc get_ip;
+ InspectSsnFunc get_user;
+ InspectSsnFunc get_file;
class ExpectCache* exp_cache;
};
//-------------------------------------------------------------------------
inline void FlowKey::init4(
- const sfip_t* srcIP, uint16_t srcPort,
- const sfip_t* dstIP, uint16_t dstPort,
- uint8_t proto, uint32_t mplsId, bool order)
+ uint8_t proto,
+ const sfip_t *srcIP, uint16_t srcPort,
+ const sfip_t *dstIP, uint16_t dstPort,
+ uint32_t mplsId, bool order)
{
const uint32_t* src;
const uint32_t* dst;
}
inline void FlowKey::init6(
- const sfip_t* srcIP, uint16_t srcPort,
- const sfip_t* dstIP, uint16_t dstPort,
- uint8_t proto, uint32_t mplsId, bool order)
+ uint8_t proto,
+ const sfip_t *srcIP, uint16_t srcPort,
+ const sfip_t *dstIP, uint16_t dstPort,
+ uint32_t mplsId, bool order)
{
const sfip_t* src;
const sfip_t* dst;
mplsLabel = 0;
}
-void FlowKey::init_vlan(uint16_t vlan)
+void FlowKey::init_vlan(uint16_t vlanId)
{
if (!SnortConfig::get_vlan_agnostic())
- vlan_tag = vlan;
+ vlan_tag = vlanId;
else
vlan_tag = 0;
}
}
void FlowKey::init(
- const sfip_t* srcIP, uint16_t srcPort,
- const sfip_t* dstIP, uint16_t dstPort,
- uint8_t proto, uint16_t vlan,
- uint32_t mplsId, uint16_t addrSpaceId)
+ uint8_t type, uint8_t proto,
+ const sfip_t *srcIP, uint16_t srcPort,
+ const sfip_t *dstIP, uint16_t dstPort,
+ uint16_t vlanId, uint32_t mplsId, uint16_t addrSpaceId)
{
/* Because the key is going to be used for hash lookups,
* the lower of the values of the IP address field is
* stored in port_l.
*/
if (srcIP->is_ip4())
- init4(srcIP, srcPort, dstIP, dstPort, proto, mplsId);
-
+ {
+ version = 4;
+ init4(proto, srcIP, srcPort, dstIP, dstPort, mplsId);
+ }
else
- init6(srcIP, srcPort, dstIP, dstPort, proto, mplsId);
+ {
+ version = 6;
+ init6(proto, srcIP, srcPort, dstIP, dstPort, mplsId);
+ }
- protocol = proto;
- version = 0;
+ protocol = type;
- init_vlan(vlan);
+ init_vlan(vlanId);
init_address_space(addrSpaceId);
}
void FlowKey::init(
- const sfip_t* srcIP, const sfip_t* dstIP,
- uint32_t id, uint8_t proto, uint16_t vlan,
+ uint8_t type, uint8_t proto,
+ const sfip_t *srcIP, const sfip_t *dstIP,
+ uint32_t id, uint16_t vlanId,
uint32_t mplsId, uint16_t addrSpaceId)
{
// to avoid confusing 2 different datagrams or confusing a datagram
if (srcIP->is_ip4())
{
version = 4;
- protocol = proto;
- init4(srcIP, srcPort, dstIP, dstPort, proto, mplsId, false);
+ init4(proto, srcIP, srcPort, dstIP, dstPort, mplsId, false);
}
else
{
version = 6;
- protocol = 0;
- init6(srcIP, srcPort, dstIP, dstPort, proto, mplsId, false);
+ init6(proto, srcIP, srcPort, dstIP, dstPort, mplsId, false);
}
+ protocol = type;
- init_vlan(vlan);
+ init_vlan(vlanId);
init_address_space(addrSpaceId);
}
struct FlowKey
{
- uint32_t ip_l[4]; /* Low IP */
- uint32_t ip_h[4]; /* High IP */
- uint16_t port_l; /* Low Port - 0 if ICMP */
- uint16_t port_h; /* High Port - 0 if ICMP */
- uint16_t vlan_tag;
- uint8_t protocol;
- uint8_t version;
- uint32_t mplsLabel; /* MPLS label */
- uint16_t addressSpaceId;
- uint16_t addressSpaceIdPad1;
+ uint32_t ip_l[4]; /* Low IP */
+ uint32_t ip_h[4]; /* High IP */
+ uint16_t port_l; /* Low Port - 0 if ICMP */
+ uint16_t port_h; /* High Port - 0 if ICMP */
+ uint16_t vlan_tag;
+ uint8_t protocol;
+ uint8_t version;
+ uint32_t mplsLabel;
+ uint16_t addressSpaceId;
+ uint16_t addressSpaceIdPad1;
void init(
- const sfip_t* srcIP, uint16_t srcPort,
- const sfip_t* dstIP, uint16_t dstPort,
- uint8_t proto, uint16_t vlan,
- uint32_t mplsId, uint16_t addrSpaceId);
+ uint8_t type, uint8_t proto,
+ const sfip_t *srcIP, uint16_t srcPort,
+ const sfip_t *dstIP, uint16_t dstPort,
+ uint16_t vlanId, uint32_t mplsId, uint16_t addrSpaceId);
void init(
- const sfip_t* srcIP, const sfip_t* dstIP,
- uint32_t id, uint8_t proto, uint16_t vlan,
+ uint8_t type, uint8_t proto,
+ const sfip_t *srcIP, const sfip_t *dstIP,
+ uint32_t id, uint16_t vlanId,
uint32_t mplsId, uint16_t addrSpaceId);
void init_mpls(uint32_t);
private:
void init4(
- const sfip_t* srcIP, uint16_t srcPort,
- const sfip_t* dstIP, uint16_t dstPort,
- uint8_t proto, uint32_t mplsId, bool order = true);
+ uint8_t proto,
+ const sfip_t *srcIP, uint16_t srcPort,
+ const sfip_t *dstIP, uint16_t dstPort,
+ uint32_t mplsId, bool order = true);
void init6(
- const sfip_t* srcIP, uint16_t srcPort,
- const sfip_t* dstIP, uint16_t dstPort,
- uint8_t proto, uint32_t mplsId, bool order = true);
+ uint8_t proto,
+ const sfip_t *srcIP, uint16_t srcPort,
+ const sfip_t *dstIP, uint16_t dstPort,
+ uint32_t mplsId, bool order = true);
};
#endif
#define SESSION_H
#include "sfip/sfip_t.h"
+#include "stream/stream_api.h"
struct Packet;
class Flow;
virtual bool add_alert(Packet*, uint32_t /*gid*/, uint32_t /*sid*/) { return false; }
virtual bool check_alerted(Packet*, uint32_t /*gid*/, uint32_t /*sid*/) { return false; }
+ virtual int update_alert(
+ Packet*, uint32_t /*gid*/, uint32_t /*sid*/,
+ uint32_t /*event_id*/, uint32_t /*event_second*/) { return 0; }
+
+ virtual void flush_client(Packet*) { }
+ virtual void flush_server(Packet*) { }
+ virtual void flush_talker(Packet*) { }
+ virtual void flush_listener(Packet*) { }
+
+ virtual void set_splitter(bool /*c2s*/, StreamSplitter*) { }
+ virtual StreamSplitter* get_splitter(bool /*c2s*/) { return nullptr; }
+
+ virtual void set_extra_data(Packet*, uint32_t /*flag*/) { }
+ virtual void clear_extra_data(Packet*, uint32_t /*flag*/) { }
+
+ virtual int get_rebuilt_packets(Packet*, PacketIterator, void* /*userdata*/) { return 0; }
+ virtual int get_segments(Packet*, StreamSegmentIterator, void* /*userdata*/) { return -1; }
+
+ virtual bool is_sequenced(uint8_t /*dir*/) { return true; }
+ virtual bool are_packets_missing(uint8_t /*dir*/) { return true; }
+
+ virtual uint8_t get_reassembly_direction() { return SSN_DIR_NONE; }
+ virtual uint8_t missing_in_reassembled(uint8_t /*dir*/) { return SSN_MISSING_NONE; }
+
protected:
Session(Flow* f) { flow = f; }
#include "framework/decode_data.h"
struct TextLog;
+struct _daq_pkthdr;
struct Packet;
struct Layer;
enum CodecSid : uint32_t;
struct RawData
{
+ const _daq_pkthdr* pkth;
const uint8_t* data;
uint32_t len;
+
+ RawData(const _daq_pkthdr*, const uint8_t*);
};
/* Decode Flags */
constexpr uint16_t CODEC_DF = 0x0001; /* don't fragment flag */
-constexpr uint16_t CODEC_UNSURE_ENCAP = 0x0002; /* packet may have incorrect encapsulation layer.
- * don't alert if "next layer" is invalid.
- * If decode fails with this bit set, PacketManager
- * will back out to the previous layer.
- * IMPORTANT: This bit can ONLY be set if the
- * DECODE_ENCAP_LAYER flag was
- * was previously set.
- */
-constexpr uint16_t CODEC_SAVE_LAYER = 0x0004; /* DO NOT USE THIS LAYER!!
- * -- use DECODE_ENCAP_LAYER
- */
+
+// packet may have incorrect encapsulation layer. don't alert if "next
+// layer" is invalid. If decode fails with this bit set, PacketManager
+// will back out to the previous layer. IMPORTANT: This bit can ONLY be
+// set if the DECODE_ENCAP_LAYER flag was was previously set.
+constexpr uint16_t CODEC_UNSURE_ENCAP = 0x0002;
+
+// DO NOT USE THIS LAYER!! -- use DECODE_ENCAP_LAYER
+constexpr uint16_t CODEC_SAVE_LAYER = 0x0004;
+
+// If encapsulation decode fails, back out to this layer This will be
+// cleared by PacketManager between decodes This flag automatically sets
+// DECODE_ENCAP_LAYER for the next layer (and only the next layer).
constexpr uint16_t CODEC_ENCAP_LAYER = (CODEC_SAVE_LAYER | CODEC_UNSURE_ENCAP );
-/* If encapsulation decode fails, back out to this layer
- * This will be cleared by PacketManager between decodes
- * This flag automatically sets DECODE_ENCAP_LAYER for
- * the next layer (and only the next layer).
- */
-constexpr uint16_t CODEC_ROUTING_SEEN = 0x0008; /* used to check ip6 extensino order */
-constexpr uint16_t CODEC_IPOPT_RR_SEEN = 0x0010; /* used by icmp4 for alerting */
-constexpr uint16_t CODEC_IPOPT_RTRALT_SEEN = 0x0020; /* used by IGMP for alerting */
-constexpr uint16_t CODEC_IPOPT_LEN_THREE = 0x0040; /* used by IGMP for alerting */
-constexpr uint16_t CODEC_TEREDO_SEEN = 0x0080; /* used in IPv6 Codec */
+
+// used to check ip6 extensino order
+constexpr uint16_t CODEC_ROUTING_SEEN = 0x0008;
+
+// used by icmp4 for alerting
+constexpr uint16_t CODEC_IPOPT_RR_SEEN = 0x0010;
+
+// used by IGMP for alerting
+constexpr uint16_t CODEC_IPOPT_RTRALT_SEEN = 0x0020;
+
+// used by IGMP for alerting
+constexpr uint16_t CODEC_IPOPT_LEN_THREE = 0x0040;
+
+// used in IPv6 Codec
+constexpr uint16_t CODEC_TEREDO_SEEN = 0x0080;
+
constexpr uint16_t CODEC_STREAM_REBUILT = 0x0100;
constexpr uint16_t CODEC_NON_IP_TUNNEL = 0x0200;
constexpr uint16_t CODEC_IPOPT_FLAGS = (CODEC_IPOPT_RR_SEEN |
- CODEC_IPOPT_RTRALT_SEEN |
- CODEC_IPOPT_LEN_THREE);
+ CODEC_IPOPT_RTRALT_SEEN | CODEC_IPOPT_LEN_THREE);
struct CodecData
{
/* NOTE: if A protocol is added, update DecodeFlags! */
enum class PktType : std::uint8_t
{
- UNKNOWN = 0x00,
- NONE = 0x00,
- IP = 0x01,
- TCP = 0x02,
- UDP = 0x04,
- ICMP = 0x08,
- ARP = 0x10,
- ANY = 0x1F,
- ANY_IP = 0x0F,
-// FREE = 0xE0,
+ NONE= 0x00,
+ IP = 0x01,
+ TCP = 0x02,
+ UDP = 0x04,
+ ICMP = 0x08,
+ ARP = 0x10,
+ USER = 0x20,
+ FILE = 0x40,
+ STREAM = 0x22,
+ ANY_IP = 0x0F,
+ ANY_SSN = 0x6F,
+ ANY = 0x7F,
+// FREE = 0x80,
};
enum DecodeFlags : std::uint16_t
{
- /* error flags */
- DECODE_ERR_CKSUM_IP = 0x0001,
- DECODE_ERR_CKSUM_TCP = 0x0002,
- DECODE_ERR_CKSUM_UDP = 0x0004,
+ DECODE_ERR_CKSUM_IP = 0x0001, // error flags
+ DECODE_ERR_CKSUM_TCP = 0x0002,
+ DECODE_ERR_CKSUM_UDP = 0x0004,
DECODE_ERR_CKSUM_ICMP = 0x0008,
- DECODE_ERR_BAD_TTL = 0x0010,
+ DECODE_ERR_BAD_TTL = 0x0010,
DECODE_ERR_CKSUM_ALL = ( DECODE_ERR_CKSUM_IP | DECODE_ERR_CKSUM_TCP |
DECODE_ERR_CKSUM_UDP | DECODE_ERR_CKSUM_ICMP ),
DECODE_ERR_FLAGS = ( DECODE_ERR_CKSUM_ALL | DECODE_ERR_BAD_TTL ),
- DECODE_PKT_TRUST = 0x0020, /* Tell Snort++ to whitelist this packet */
- DECODE_FRAG = 0x0040, /* flag to indicate a fragmented packet */
- DECODE_MF = 0x0080,
+ DECODE_PKT_TRUST = 0x0020, // whitelist this packet
+ DECODE_FRAG = 0x0040, // ip - fragmented packet
+ DECODE_MF = 0x0080, // ip - more fragments
+
+ // using decode flags in lieu of creating user layer for now
+ DECODE_C2S = 0x0100, // user - client to server
+ DECODE_SOF = 0x0200, // user - start of flow
+ DECODE_EOF = 0x0400, // user - end of flow
};
// FIXIT-L J make this an enum!!
struct DecodeData
{
- /* Pointers which will be used by Snort++. (starting with uint16_t so tcph is 64 bytes from
- start*/
-
/*
- * these four pounters are each referenced literally
+ * these three pointers are each referenced literally
* dozens if not hundreds of times. NOTHING else should be added!!
*/
const tcp::TCPHdr* tcph;
const udp::UDPHdr* udph;
const icmp::ICMPHdr* icmph;
+
uint16_t sp; /* source port (TCP/UDP) */
uint16_t dp; /* dest port (TCP/UDP) */
+
uint16_t decode_flags;
PktType type;
{ return type; }
};
-#endif /* FRAMEWORK_DECODE_DATA_H */
+#endif
/* ...only_reassembled */
if (fcd->only_reassembled & ONLY_STREAM)
{
- if ( !(p->packet_flags & PKT_REBUILT_STREAM)
- && !PacketHasFullPDU(p)
- )
+ if ( !(p->packet_flags & PKT_REBUILT_STREAM) && !p->is_full_pdu() )
{
MODULE_PROFILE_END(flowCheckPerfStats);
return DETECTION_OPTION_NO_MATCH;
int rval = DETECTION_OPTION_NO_MATCH;
PROFILE_VARS;
- if (!p->ptrs.ip_api.is_valid())
+ if(!p->ptrs.ip_api.is_ip())
{
return rval;
}
//--------------------------------------------------------------------------
-// Copyright (C) 2003 Brian Caswell <bmc@snort.org>
-// Copyright (C) 2003 Michael J. Pomraning <mjp@securepipe.com>
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
// Copyright (C) 2003-2013 Sourcefire, Inc.
+// Copyright (C) 2003 Brian Caswell <bmc@snort.org>
+// Copyright (C) 2003 Michael J. Pomraning <mjp@securepipe.com>
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
PROFILE_VARS;
MODULE_PROFILE_START(replacePerfStats);
- if ( PacketWasCooked(p) )
+ if ( p->is_cooked() )
return false;
if ( !c.is("pkt_data") )
int rval = DETECTION_OPTION_NO_MATCH;
PROFILE_VARS;
- if (!p->ptrs.ip_api.is_valid())
+ if(!p->ptrs.ip_api.is_ip())
return rval;
MODULE_PROFILE_START(ipTosPerfStats);
int rval = DETECTION_OPTION_NO_MATCH;
PROFILE_VARS;
- if (!p->ptrs.ip_api.is_valid())
+ if(!p->ptrs.ip_api.is_ip())
return rval;
MODULE_PROFILE_START(ttlCheckPerfStats);
void snort_print(Packet* p)
{
- if (p->ptrs.ip_api.is_valid())
+ if (p->ptrs.ip_api.is_ip())
{
LogIPPkt(text_log, p);
}
*/
void LogIpAddrs(TextLog* log, Packet* p)
{
- if (!p->has_ip())
- return;
-
if ( p->is_fragment() || ( !p->is_tcp() && !p->is_udp()))
{
const char* ip_fmt = "%s -> %s";
*/
void LogIPHeader(TextLog* log, Packet* p)
{
- if (!p->ptrs.ip_api.is_valid())
+ if(!p->ptrs.ip_api.is_ip())
{
TextLog_Print(log, "IP header truncated\n");
return;
/* dump the TCP options */
#ifdef REG_TEST
// emulate snort bug
- if ( !PacketWasCooked(p) || (p->pseudo_type == PSEUDO_PKT_IP) )
+ if ( !p->is_cooked() || (p->pseudo_type == PSEUDO_PKT_IP) )
#endif
if (tcph->has_options())
{
{
TextLog_NewLine(log);
- if ( !p->dsize || !PacketWasCooked(p) )
+ if ( !p->dsize || !p->is_cooked() )
return;
switch ( p->pseudo_type )
break;
}
}
+ LogPayload(log, p);
+}
+void LogPayload(TextLog* log, Packet* p)
+{
if ((p->dsize > 0) && obApi->payloadObfuscationRequired(p)
&& (LogObfuscatedData(log, p) == 0))
{
void LogXrefs(TextLog*, const Event*, bool doNewLine);
void LogIPPkt(TextLog*, Packet*);
+void LogPayload(TextLog*, Packet*);
void LogNetData(TextLog*, const uint8_t* data, const int len, Packet*);
void LogTimeStamp(TextLog*, Packet*);
{
/* Log whether or not this is reassembled data - only indicate
* if we're actually going to show any of the payload */
- if ( !SnortConfig::output_app_data() || !p->dsize || !PacketWasCooked(p) )
+ if ( !SnortConfig::output_app_data() || !p->dsize || !p->is_cooked() )
return;
switch ( p->pseudo_type )
TextLog_Print(fast_log, "%s\n", "Frag reassembled packet");
break;
default:
- // FIXTHIS do we get here for portscan or sdf?
+ // FIXIT do we get here for portscan or sdf?
break;
}
}
#endif
#ifndef REG_TEST
-
static const char* get_pkt_type(Packet* p)
{
switch ( p->ptrs.get_pkt_type() )
}
return "error";
}
-
#endif
void FastLogger::alert(Packet* p, const char* msg, Event* event)
}
/* print the packet header to the alert file */
- if ( p->has_ip() )
{
LogPriorityData(fast_log, event, 0);
#ifndef REG_TEST
#endif
if (p->has_ip())
LogIPPkt(fast_log, p);
+ else
+ LogPayload(fast_log, p);
#if 0
// FIXIT-L -J LogArpHeader unimplemented
void load_sar(Packet* packet, Event* event, SnortActionRequest& sar)
{
- if (!event || !packet || !packet->ptrs.ip_api.is_valid())
+ if(!event || !packet || !packet->ptrs.ip_api.is_ip())
return;
// for now, only support ip4
SnortSnprintfAppend(event_string, sizeof(event_string),
"<%s> ", PRINT_INTERFACE(DAQ_GetInterfaceSpec()));
}
-
+ }
+ if ((p != NULL) && p->ptrs.ip_api.is_ip())
+ {
uint16_t proto = p->get_ip_proto_next();
if (protocol_names[proto] != NULL)
{
alertdata.ip_source = iph->get_src();
alertdata.ip_destination = iph->get_dst();
- if (IsPortscanPacket(p))
+ if (p->is_portscan())
{
alertdata.protocol = p->ps_proto;
}
alertdata.sport_itype = htons(p->ptrs.icmph->type);
alertdata.dport_icode = htons(p->ptrs.icmph->code);
}
- else if (!IsPortscanPacket(p))
+ else if (!p->is_portscan())
{
alertdata.sport_itype = htons(p->ptrs.sp);
alertdata.dport_icode = htons(p->ptrs.dp);
{
alertdata.blocked = GetU2Flags(p, &alertdata.impact_flag);
- if (p->ptrs.ip_api.is_valid())
+ if(p->ptrs.ip_api.is_ip())
{
const sfip_t* ip;
ip = p->ptrs.ip_api.get_dst();
alertdata.ip_destination = *(struct in6_addr*)ip->ip32;
- if (IsPortscanPacket(p))
+ if (p->is_portscan())
{
alertdata.protocol = p->ps_proto;
}
alertdata.sport_itype = htons(p->ptrs.icmph->type);
alertdata.dport_icode = htons(p->ptrs.icmph->code);
}
- else if (!IsPortscanPacket(p))
+ else if (!p->is_portscan())
{
alertdata.sport_itype = htons(p->ptrs.sp);
alertdata.dport_icode = htons(p->ptrs.dp);
//-------------------------------------------------------------------------
// file_id module
//-------------------------------------------------------------------------
+
static const Parameter file_magic_params[] =
{
{ "content", Parameter::PT_STRING, nullptr, nullptr,
{ "block_timeout_lookup", Parameter::PT_BOOL, nullptr, "false",
"block if lookup times out" },
-#if defined(DEBUG_MSGS) || defined (REG_TEST)
{ "enable_type", Parameter::PT_BOOL, nullptr, "false",
"enable type ID" },
{ "show_data_depth", Parameter::PT_INT, "0:", "100",
"print this many octets" },
-#endif
+
{ "file_rules", Parameter::PT_LIST, file_rule_params, nullptr,
"list of file magic rules" },
+ { "trace_type", Parameter::PT_BOOL, nullptr, "false",
+ "enable runtime dump of type info" },
+
+ { "trace_signature", Parameter::PT_BOOL, nullptr, "false",
+ "enable runtime dump of signature info" },
+
+ { "trace_stream", Parameter::PT_BOOL, nullptr, "false",
+ "enable runtime dump of file data" },
+
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
else if ( v.is("block_timeout_lookup") )
fc->block_timeout_lookup = v.get_bool();
-#if defined(DEBUG_MSGS) || defined (REG_TEST)
else if ( v.is("enable_type") )
- file_api->enable_file_type(nullptr);
-
+ {
+ if ( v.get_bool() )
+ file_api->enable_file_type(nullptr);
+ }
else if ( v.is("enable_signature") )
- file_api->enable_file_signature(nullptr);
-
+ {
+ if ( v.get_bool() )
+ file_api->enable_file_signature(nullptr);
+ }
else if ( v.is("show_data_depth") )
- fc->show_data_depth = v.get_long();
-#endif
+ FileConfig::show_data_depth = v.get_long();
+
+ else if ( v.is("trace_type") )
+ FileConfig::trace_type = v.get_bool();
+
+ else if ( v.is("trace_signature") )
+ FileConfig::trace_signature = v.get_bool();
+
+ else if ( v.is("trace_stream") )
+ FileConfig::trace_stream = v.get_bool();
+
else if ( v.is("file_rules") )
return true;
if ( !strcmp(fqn, "file_id.file_rules") )
{
fc->process_file_rule(rule);
- fc->print_file_rule(rule);
+ //fc->print_file_rule(rule);
}
else if ( !strcmp(fqn, "file_id.file_rules.magic") )
OUTPUT_FLAG__NO_ALERT = 0x00001000, /* -A none */
OUTPUT_FLAG__NO_LOG = 0x00002000, /* -K none */
+ OUTPUT_FLAG__ALERTS = 0x00004000, /* -A != none */
};
enum LoggingFlag
"<port> to listen for telnet connections" },
#endif
- { "-K", Parameter::PT_SELECT, "none|text|pcap", "none",
- "<mode> logging mode" },
-
{ "-k", Parameter::PT_ENUM, "all|noip|notcp|noudp|noicmp|none", "all",
"<mode> checksum mode (all,noip,notcp,noudp,noicmp,none)" },
+ { "-L", Parameter::PT_STRING, nullptr, nullptr,
+ "<mode> logging mode (none, text, pcap, or log_*)" },
+
{ "-l", Parameter::PT_STRING, nullptr, nullptr,
"<logdir> log to this directory instead of current directory" },
sc->remote_control = v.get_long();
#endif
- else if ( v.is("-K") )
- config_log_mode(sc, v.get_string());
-
else if ( v.is("-k") )
ConfigChecksumMode(sc, v.get_string());
+ else if ( v.is("-L") )
+ config_log_mode(sc, v.get_string());
+
else if ( v.is("-l") )
ConfigLogDir(sc, v.get_string());
}
}
- if (!grinder)
- ParseError("PacketManager: Unable to find a Codec with data link type %d\n", daq_dlt);
+ if(!grinder)
+ ParseError("Unable to find a Codec with data link type %d\n", daq_dlt);
#ifndef VALGRIND_TESTING
if ( s_rand )
s_rand = rand_open();
if ( !s_rand )
- ParseError("PacketManager::init: rand_open() failed.\n");
+ ParseError("rand_open() failed.\n");
rand_get(s_rand, s_id_pool.data(), s_id_pool.size());
#endif
if ( !strcasecmp(p->api->base.name, key) )
return p;
- return NULL;
+ return nullptr;
+}
+
+static Output* get_out(const char* key, const char* pfx)
+{
+ Output* p = get_out(key);
+
+ if ( p )
+ return p;
+
+ if ( !strncmp(key, pfx, strlen(pfx)) )
+ return nullptr;
+
+ string s = pfx;
+ s += key;
+
+ p = get_out(s.c_str());
+
+ return p;
}
unsigned EventManager::get_output_type_flags(char* key)
// override prior outputs
// (last cmdline option wins)
s_loggers.outputs.clear();
+ string tmp = name;
- Output* p = get_out(name);
+ const char* pfx = (sc->output_flags & OUTPUT_FLAG__ALERTS) ? "alert_" : "log_";
+ Output* p = get_out(name, pfx);
if ( !p )
{
ParseError("unknown logger %s\n", name);
return;
}
- else if ( p->handler )
+
+ sc->output = name = p->api->base.name;
+
+ if ( p->handler )
{
// configured by conf
s_loggers.outputs.push_back(p->handler);
if ( udp )
m->add((unsigned)PktType::UDP, wiz_id);
+ if ( tcp or udp )
+ m->add((unsigned)PktType::USER, wiz_id);
+
const InspectApi* api = get_plugin(bind_id);
InspectorManager::instantiate(api, m, sc);
fp->binder = get_instance(fp, bind_id)->handler;
if ( !p->flow && (ppc.api.type == IT_SERVICE) )
break;
- if ( ((unsigned)p->type() & ppc.api.proto_bits) )
+ if ( (unsigned)p->type() & ppc.api.proto_bits )
(*prep)->handler->eval(p);
}
}
+// FIXIT-L use inspection events instead of exec
void InspectorManager::bumble(Packet* p)
{
Flow* flow = p->flow;
flow->clear_clouseau();
- if ( !flow->gadget || flow->protocol != PktType::TCP )
+ if ( !flow->gadget || !flow->is_stream() )
return;
if ( flow->session )
DisableDetect(p);
// FIXIT-M need list of gadgets for ambiguous wizardry
- else if ( flow->gadget && PacketHasPAFPayload(p) )
+ else if ( flow->gadget && p->has_paf_payload() )
{
flow->gadget->eval(p);
s_clear = true;
assert(fp);
// FIXIT-L blocked flows should not be normalized
- if ( !PacketWasCooked(p) )
+ if ( !p->is_cooked() )
::execute(p, fp->packet.vec, fp->packet.num);
- if ( !PacketHasPAFPayload(p) )
+ if ( !p->has_paf_payload() )
::execute(p, fp->session.vec, fp->session.num);
Flow* flow = p->flow;
{ "nets", Parameter::PT_ADDR_LIST, nullptr, nullptr,
"list of networks" },
- { "proto", Parameter::PT_ENUM, "any | ip | icmp | tcp | udp", nullptr,
+ { "proto", Parameter::PT_ENUM, "any | ip | icmp | tcp | udp | user | file", nullptr,
"protocol" },
{ "ports", Parameter::PT_BIT_LIST, "65535", nullptr,
else if ( v.is("proto") )
{
const PktType mask[] =
- {
- PktType::ANY, PktType::IP, PktType::ICMP, PktType::TCP, PktType::UDP
+ {
+ PktType::ANY, PktType::IP, PktType::ICMP, PktType::TCP, PktType::UDP,
+ PktType::USER, PktType::FILE
};
work->when.protos = (unsigned)mask[v.get_long()];
}
#include "flow/flow.h"
#include "flow/session.h"
#include "framework/inspector.h"
-#include "stream/stream_splitter.h"
#include "managers/inspector_manager.h"
#include "managers/plugin_manager.h"
#include "protocols/packet.h"
#include "protocols/vlan.h"
#include "protocols/layer.h"
#include "stream/stream_api.h"
+#include "stream/stream_splitter.h"
#include "time/profiler.h"
#include "utils/stats.h"
#include "log/messages.h"
#define INS_ICMP "stream_icmp"
#define INS_TCP "stream_tcp"
#define INS_UDP "stream_udp"
+#define INS_USER "stream_user"
+#define INS_FILE "stream_file"
//-------------------------------------------------------------------------
// binding
set_session(flow, INS_UDP);
break;
+ case PktType::USER:
+ set_session(flow, INS_USER);
+ break;
+
+ case PktType::FILE:
+ set_session(flow, INS_FILE);
+ break;
+
default:
set_session(flow);
}
if ( ins )
flow->set_gadget(ins);
- if ( flow->protocol != PktType::TCP )
+ if ( !flow->is_stream() )
return 0;
if ( ins )
extern const BaseApi* nin_binder;
extern const BaseApi* nin_normalize;
extern const BaseApi* nin_perf_monitor;
-extern const BaseApi* nin_stream_ip;
-extern const BaseApi* nin_stream_icmp;
-extern const BaseApi* nin_stream_tcp;
-extern const BaseApi* nin_stream_udp;
extern const BaseApi* nin_port_scan_global;
extern const BaseApi* nin_port_scan;
-extern const BaseApi* ips_stream_reassemble;
-extern const BaseApi* ips_stream_size;
-
#ifdef STATIC_INSPECTORS
extern const BaseApi* nin_arp_spoof;
#endif
nin_binder,
nin_normalize,
nin_perf_monitor,
- nin_stream_ip,
- nin_stream_icmp,
- nin_stream_tcp,
- nin_stream_udp,
nin_port_scan_global,
nin_port_scan,
- ips_stream_reassemble,
- ips_stream_size,
-
#ifdef STATIC_INSPECTORS
nin_arp_spoof,
#endif
PROFILE_VARS;
MODULE_PROFILE_START(norm_perf_stats);
- if ( !PacketIsRebuilt(p) && !Active_PacketWasDropped() )
+ if ( !p->is_rebuilt() && !Active_PacketWasDropped() )
Norm_Packet(&config, p);
MODULE_PROFILE_END(norm_perf_stats);
// stream have been added.
UpdatePerfStats(sfPerf, p);
- if ((sfPerf->perf_flags & SFPERF_TIME_COUNT) && !PacketIsRebuilt(p))
+ if ((sfPerf->perf_flags & SFPERF_TIME_COUNT) && !p->is_rebuilt())
{
static THREAD_LOCAL uint32_t cnt = 0;
static void UpdatePerfStats(SFPERF* sfPerf, Packet* p)
{
perfmon_config = sfPerf; // FIXIT-L sfPerf isn't propagated far enough
- bool rebuilt = PacketIsRebuilt(p);
+ bool rebuilt = p->is_rebuilt();
if (sfPerf->perf_flags & SFPERF_BASE)
UpdateBaseStats(&sfBase, p, rebuilt);
const sfip_t* src_addr;
const sfip_t* dst_addr;
- if (!p->ptrs.ip_api.is_valid())
+ if(!p->ptrs.ip_api.is_ip())
return -1;
/* Do not log if being suppressed */
}
else
{
- // since ip_api.is_valid() && !ip4h, this is automatically ip6h
+ // since ip_api.is_ip() && !ip4h, this is automatically ip6h
((ip::IP6Hdr*)g_tmp_pkt->ptrs.ip_api.get_ip6h())->set_proto(IPPROTO_PS);
}
PS_PKT ps_pkt;
PROFILE_VARS;
- assert(p->ptrs.ip_api.is_valid());
+ assert(p->ptrs.ip_api.is_ip());
if ( p->packet_flags & PKT_REBUILT_STREAM )
return;
mod_dtor
},
IT_PROBE,
- (uint16_t)PktType::ANY_IP, // FIXIT-L dynamic assign
+ (uint16_t)PktType::IP,
nullptr, // buffers
nullptr, // service
nullptr, // pinit
p = (Packet*)ps_pkt->pkt;
- if (!p->ptrs.ip_api.is_valid())
+ if(!p->ptrs.ip_api.is_ip())
return 1;
if (p->ptrs.tcph)
if (config->detect_scans & PS_PROTO_IP)
{
- if ((p->ptrs.ip_api.is_valid() && (p->ptrs.icmph == NULL))
- || ((p->ptrs.icmph != NULL) && (p->ptrs.icmph->type == ICMP_DEST_UNREACH)
- && ((p->ptrs.icmph->code == ICMP_PROT_UNREACH)
- || (p->ptrs.icmph->code == ICMP_PKT_FILTERED))))
+ if ((p->ptrs.ip_api.is_ip() && (p->ptrs.icmph == NULL))
+ || ((p->ptrs.icmph != NULL) && (p->ptrs.icmph->type == ICMP_DEST_UNREACH)
+ && ((p->ptrs.icmph->code == ICMP_PROT_UNREACH)
+ || (p->ptrs.icmph->code == ICMP_PKT_FILTERED))))
{
*proto = PS_PROTO_IP;
return 0;
p = (Packet*)ps_pkt->pkt;
- if (p->ptrs.ip_api.is_valid())
+ if(p->ptrs.ip_api.is_ip())
{
if (p->ptrs.icmph)
{
switch ( p->type() )
{
- case PktType::UNKNOWN:
+ case PktType::NONE:
// Can only occur if we have never seen IP
return;
if ( !Active_IsEnabled() )
return 0;
- if ( !p->ptrs.ip_api.is_valid() )
+ if ( !p->ptrs.ip_api.is_ip() )
return 0;
switch ( p->type() )
int err = 0;
static mutex bpf_gate;
- bpf_gate.lock();
// doesn't look like the bpf flex scanner is reentrant
+ bpf_gate.lock();
- if ( bpf )
+ if ( bpf and *bpf )
err = daq_set_filter(daq_mod, daq_hand, bpf);
bpf_gate.unlock();
(strcasecmp(val, ALERT_JH) == 0) ||
(strcasecmp(val, ALERT_DJR) == 0))
{
- sc->output = SnortStrdup(OUTPUT_CMG);
+ sc->output = OUTPUT_CMG;
sc->output_flags |= OUTPUT_FLAG__SHOW_DATA_LINK;
sc->output_flags |= OUTPUT_FLAG__APP_DATA;
}
else if (strcasecmp(val, ALERT_AJK) == 0)
- sc->output = SnortStrdup(OUTPUT_AJK);
+ sc->output = OUTPUT_AJK;
#ifdef REG_TEST
else if (strcasecmp(val, ALERT_CON) == 0)
- sc->output = SnortStrdup("alert_fast");
+ sc->output = "alert_fast";
#endif
else
- sc->output = SnortStrdup(val);
+ sc->output = val;
+
+ sc->output_flags |= OUTPUT_FLAG__ALERTS;
+ Snort::set_main_hook(snort_inspect);
}
void config_log_mode(SnortConfig* sc, const char* val)
}
else if (strcasecmp(val, LOG_PCAP) == 0)
{
- sc->output = SnortStrdup(OUTPUT_PCAP);
+ sc->output = OUTPUT_PCAP;
Snort::set_main_hook(snort_log);
}
else
{
- FatalError("Unknown -K option: %s\n", val);
+ sc->output = val;
+ Snort::set_main_hook(snort_log);
}
}
#include <arpa/inet.h>
#include "protocols/ip.h"
#include "protocols/packet.h"
+#include "sfip/sf_ip.h"
namespace ip
{
void IpApi::reset()
{
- ip4h = nullptr;
- ip6h = nullptr;
- src_p = nullptr;
- dst_p = nullptr;
+ type = IAT_NONE;
+ iph = nullptr;
}
void IpApi::set(const IP4Hdr* h4)
{
- ip4h = h4;
- ip6h = nullptr;
+ iph = (const void*)h4;
+ type = IAT_4;
src.family = AF_INET;
src.bits = 32;
- src.ip32[0] = *(uint32_t*)(&ip4h->ip_src);
+ src.ip32[0] = *(uint32_t*)(&h4->ip_src);
std::memset(&(src.ip32[1]), 0, 12);
- src_p = &src;
dst.family = AF_INET;
dst.bits = 32;
- dst.ip32[0] = *(uint32_t*)(&ip4h->ip_dst);
+ dst.ip32[0] = *(uint32_t*)(&h4->ip_dst);
std::memset(&(dst.ip32[1]), 0, 12);
- dst_p = &dst;
}
void IpApi::set(const ip::IP6Hdr* h6)
{
- ip6h = h6;
- ip4h = nullptr;
+ iph = (const void*)h6;
+ type = IAT_6;
src.family = AF_INET6;
src.bits = 128;
- std::memcpy(&(src.ip8), &(ip6h->ip6_src), 16);
- src_p = &src;
+ std::memcpy(&(src.ip8), &(h6->ip6_src), 16);
dst.family = AF_INET6;
dst.bits = 128;
- std::memcpy(&(dst.ip8), &(ip6h->ip6_dst), 16);
- dst_p = &dst;
+ std::memcpy(&(dst.ip8), &(h6->ip6_dst), 16);
+}
+
+void IpApi::set(sfip_t& sip, sfip_t& dip)
+{
+ type = IAT_DATA;
+ sfip_set_ip(&src, &sip);
+ sfip_set_ip(&dst, &dip);
+ iph = nullptr;
}
bool IpApi::set(const uint8_t* raw_ip_data)
{
const IP4Hdr* h4 = reinterpret_cast<const IP4Hdr*>(raw_ip_data);
+
if (h4->ver() == 4)
{
set(h4);
set(h6);
return true;
}
-
return false;
}
+uint16_t IpApi::tos() const
+{
+ switch ( type )
+ {
+ case IAT_4: return ((IP4Hdr*)iph)->tos();
+ case IAT_6: return ((IP6Hdr*)iph)->tos();
+ default: break;
+ }
+ return 0;
+}
+
+uint8_t IpApi::ttl() const
+{
+ switch ( type )
+ {
+ case IAT_4: return ((IP4Hdr*)iph)->ttl();
+ case IAT_6: return ((IP6Hdr*)iph)->hop_lim();
+ default: break;
+ }
+ return 0;
+}
+
+/* This is different than the Packet's ip_proto_next field - this
+ * variable hold the first non-ip and non-ipv6 extension protocols,
+ * while proto() returns the next or proto() field of the raw IP
+ * header */
+uint8_t IpApi::proto() const
+{
+ switch ( type )
+ {
+ case IAT_4: return ((IP4Hdr*)iph)->proto();
+ case IAT_6: return ((IP6Hdr*)iph)->next();
+ default: break;
+ }
+ return 0xFF;
+}
+
+// header length field: datagram/payload-only length for 4/6
+// you may want pay_len() or dgram_len() instead
+uint16_t IpApi::raw_len() const
+{
+ switch ( type )
+ {
+ case IAT_4: return ((IP4Hdr*)iph)->raw_len();
+ case IAT_6: return ((IP6Hdr*)iph)->raw_len();
+ default: break;
+ }
+ return 0;
+}
+
+uint8_t IpApi::hlen() const
+{
+ switch ( type )
+ {
+ case IAT_4: return ((IP4Hdr*)iph)->hlen();
+ case IAT_6: return ((IP6Hdr*)iph)->hlen();
+ default: break;
+ }
+ return 0;
+}
+
+uint8_t IpApi::ver() const
+{
+ switch ( type )
+ {
+ case IAT_4: return ((IP4Hdr*)iph)->ver();
+ case IAT_6: return ((IP6Hdr*)iph)->ver();
+ default: break;
+ }
+ return 0;
+}
+
+bool operator==(const IpApi& lhs, const IpApi& rhs)
+{
+ if ( lhs.type != rhs.type )
+ return false;
+
+ // FIXIT-H is this really supposed to be a shallow compare?
+ return ( lhs.iph == rhs.iph );
+}
+
+bool operator!=(const IpApi& lhs, const IpApi& rhs)
+{ return !(lhs == rhs); }
+
uint32_t IpApi::id() const
{
- if (ip4h)
- return (uint32_t)ip4h->id();
+ if ( type == IAT_4 )
+ return (uint32_t)((IP4Hdr*)iph)->id();
+
+ if ( type != IAT_6 )
+ return 0;
const IP6Frag* const frag_hdr = layer::get_inner_ip6_frag();
if (frag_hdr)
return frag_hdr->id();
+
return 0;
}
uint16_t IpApi::off() const
{
- if (ip4h)
- return ip4h->off();
+ if ( type == IAT_4 )
+ return (uint32_t)((IP4Hdr*)iph)->off();
+
+ if ( type != IAT_6 )
+ return 0;
const IP6Frag* const frag_hdr = layer::get_inner_ip6_frag();
- if (frag_hdr)
+ if ( frag_hdr )
return frag_hdr->off();
+
return 0;
}
uint16_t IpApi::off_w_flags() const
{
- if (ip4h)
- return ip4h->off_w_flags();
+ if ( type == IAT_4 )
+ return (uint32_t)((IP4Hdr*)iph)->off_w_flags();
+
+ if ( type != IAT_6 )
+ return 0;
const IP6Frag* const frag_hdr = layer::get_inner_ip6_frag();
- if (frag_hdr)
+ if ( frag_hdr )
return frag_hdr->off_w_flags();
+
return 0;
}
const uint8_t* IpApi::ip_data() const
{
- if (ip4h)
- return reinterpret_cast<const uint8_t*>(ip4h) + ip4h->hlen();
-
- if (ip6h)
- return reinterpret_cast<const uint8_t*>(ip6h) + ip6h->hlen();
-
+ switch ( type )
+ {
+ case IAT_4: return reinterpret_cast<const uint8_t*>(iph) + ((IP4Hdr*)iph)->hlen();
+ case IAT_6: return reinterpret_cast<const uint8_t*>(iph) + ((IP6Hdr*)iph)->hlen();
+ default: break;
+ }
return nullptr;
}
uint16_t IpApi::actual_ip_len() const
{
- if (ip4h)
- return ip4h->len();
-
- if (ip6h)
- return ip6h->len();
-
+ switch ( type )
+ {
+ case IAT_4: return ((IP4Hdr*)iph)->len();
+ case IAT_6: return ((IP6Hdr*)iph)->len();
+ default: break;
+ }
return 0;
}
uint16_t IpApi::dgram_len() const
{
- if (ip4h)
- return ip4h->len();
-
- if (ip6h)
- return ip6h->len() + IP6_HEADER_LEN;
-
+ switch ( type )
+ {
+ case IAT_4: return ((IP4Hdr*)iph)->len();
+ case IAT_6: return ((IP6Hdr*)iph)->len() + IP6_HEADER_LEN;
+ default: break;
+ }
return 0;
}
uint16_t IpApi::pay_len() const
{
- if (ip4h)
- return ip4h->len() - ip4h->hlen();
-
- if (ip6h)
- return ip6h->len();
-
+ switch ( type )
+ {
+ case IAT_4: return ((IP4Hdr*)iph)->len() - ((IP4Hdr*)iph)->hlen();
+ case IAT_6: return ((IP6Hdr*)iph)->len();
+ default: break;
+ }
return 0;
}
-static bool is_ip6_loopback(const snort_in6_addr* const ip)
+static inline bool is_loopback(uint32_t addr)
+{ return (addr >> 24) == 0x7F; }
+
+static bool is_loopback(const snort_in6_addr* const ip)
{
const uint32_t* p = ip->u6_addr32;
return false;
/* Check if the 3rd 32-bit int is zero */
- if ( p[2] == 0 )
- {
- /* ::7f00:0/104 is ipv4 compatible ipv6
- ::1 is the IPv6 loopback */
- return ( (ip->u6_addr8[12] == 0x7f) || (ntohl(p[3]) == 0x1) );
+ if ( p[2] == 0 ) {
+ /* ::7F00:0/104 is ipv4 compatible ipv6 */
+ /* ::1 is the IPv6 loopback */
+ return ( (ip->u6_addr8[12] == 0x7F) || (ntohl(p[3]) == 0x1) );
}
/* Check the 3rd 32-bit int for a mapped IPv4 address */
if ( ntohl(p[2]) == 0xffff )
{
/* ::ffff:127.0.0.0/104 is IPv4 loopback mapped over IPv6 */
- return ( ip->u6_addr8[12] == 0x7f );
+ return ( ip->u6_addr8[12] == 0x7F );
}
return false;
}
bool IpApi::is_src_loopback() const
{
- if (ip4h)
- return ((ntohl(ip4h->get_src())) >> 24) == 0x7f;
-
- if (ip6h)
- return is_ip6_loopback(ip6h->get_src());
-
+ switch ( type )
+ {
+ case IAT_4: return is_loopback(ntohl(((IP4Hdr*)iph)->get_src()));
+ case IAT_6: return is_loopback(((IP6Hdr*)iph)->get_src());
+ default: break;
+ }
return false;
}
// true if the current source address ia the loopback address
bool IpApi::is_dst_loopback() const
{
- if (ip4h)
- return ((ntohl(ip4h->get_dst())) >> 24) == 0x7f;
-
- if (ip6h)
- return is_ip6_loopback(ip6h->get_dst());
-
+ switch ( type )
+ {
+ case IAT_4: return ((ntohl(((IP4Hdr*)iph)->get_dst())) >> 24) == 0x7F;
+ case IAT_6: return is_loopback(((IP6Hdr*)iph)->get_dst());
+ default: break;
+ }
return false;
}
} // namespace ip
class SO_PUBLIC IpApi
{
public:
-// IpApi(); constructor and destructor MUST remain a trivial. Adding
-// ~IpApi(); any non-trivial code will cause a compilation failure.
+ enum Type { IAT_NONE, IAT_4, IAT_6, IAT_DATA };
+
+ // constructor and destructor MUST remain a trivial. Adding
+ // any non-trivial code will cause a compilation failure.
IpApi() = default;
void set(const IP4Hdr* h4);
void set(const IP6Hdr* h6);
+ void set(sfip_t& src, sfip_t& dst);
bool set(const uint8_t* raw_ip_data);
void reset();
+
// return the 16 bits associated with this IP layers frag_offset/flags
uint16_t off_w_flags() const;
// return the frag_offset associated with this IP layers in word size.
const uint8_t* ip_data() const; // return a pointer to the ip layers data
// FIXIT-L J get rid of the unnecessary ones
- // returns the length of the ip header + length in host byte order
+ // returns the sum of the ip header + payload lengths in host byte order
uint16_t dgram_len() const;
// returns this ip layer's payload length in host byte order
uint16_t pay_len() const;
bool is_src_loopback() const;
// true if the current source address ia the loopback address
bool is_dst_loopback() const;
+
// overloaded == operators.
friend bool operator==(const IpApi& lhs, const IpApi& rhs);
friend bool operator!=(const IpApi& lhs, const IpApi& rhs);
// returns true if this api is set.
inline bool is_valid() const
- { return (ip4h || ip6h); }
+ { return (type != IAT_NONE); }
inline bool is_ip6() const
- { return ip6h; }
+ { return (type == IAT_6); }
inline bool is_ip4() const
- { return ip4h; }
+ { return (type == IAT_4); }
+
+ inline bool is_ip() const
+ { return is_ip4() or is_ip6(); }
inline const IP4Hdr* get_ip4h() const
- { return ip4h; }
+ { return (type == IAT_4) ? (IP4Hdr*)iph : nullptr; }
inline const IP6Hdr* get_ip6h() const
- { return ip6h; }
+ { return (type == IAT_6) ? (IP6Hdr*)iph : nullptr; }
inline const sfip_t* get_src() const
- { return src_p; }
+ { return (type != IAT_NONE) ? &src : nullptr; }
inline const sfip_t* get_dst() const
- { return dst_p; }
-
- inline uint16_t tos() const
- { return ip4h ? ip4h->tos() : ip6h ? ip6h->tos() : 0; }
-
- inline uint8_t ttl() const
- { return ip4h ? ip4h->ttl() : ip6h ? ip6h->hop_lim() : 0; }
-
- /* This is different than the Packet's ip_proto_next field - this
- * variable hold the first non-ip and non-ipv6 extension protocols,
- * while proto() returns the next or proto() field of the raw IP
- * header */
- inline uint8_t proto() const
- { return ip4h ? ip4h->proto() : ip6h ? ip6h->next() : 0xFF; }
+ { return (type != IAT_NONE) ? &dst : nullptr; }
- // NOTE: ipv4 len contains header while an ipv6 header does not. If you
- // want a length, use 'dgram_len() == length with header' or
- // 'pay_len() == length without header' instead.
-// inline uint16_t len() const
-// { return ip4h ? ip4h->len() : ip6h ? ip6h->len() : 0; }
-
- inline uint16_t raw_len() const
- { return ip4h ? ip4h->raw_len() : ip6h ? ip6h->raw_len() : 0; }
-
- inline uint8_t hlen() const
- { return ip4h ? ip4h->hlen() : ip6h ? ip6h->hlen() : 0; }
-
- inline uint8_t ver() const
- { return ip4h ? ip4h->ver() : ip6h ? ip6h->ver() : 0; }
-
- // only relevent to IP4.
+ // only relevant to IP4
inline uint8_t get_ip_opt_len() const
- { return ip4h ? ip4h->get_opt_len() : 0; }
+ { return (type == IAT_4) ? ((IP4Hdr*)iph)->get_opt_len() : 0; }
- // only relevent to IP4.
+ // only relevant to IP4
inline const uint8_t* get_ip_opt_data() const
- { return ip4h ? reinterpret_cast<const uint8_t*>(ip4h) + IP4_HEADER_LEN : nullptr; }
+ { return (type == IAT_4) ? reinterpret_cast<const uint8_t*>(iph) + IP4_HEADER_LEN : nullptr; }
inline const snort_in6_addr* get_ip6_src() const
- { return ip6h ? ip6h->get_src() : nullptr; }
+ { return (type == IAT_6) ? ((IP6Hdr*)iph)->get_src() : nullptr; }
inline const snort_in6_addr* get_ip6_dst() const
- { return ip6h ? ip6h->get_dst() : nullptr; }
+ { return (type == IAT_6) ? ((IP6Hdr*)iph)->get_dst() : nullptr; }
+
+ uint16_t tos() const;
+ uint8_t ttl() const;
+ uint8_t proto() const;
+ uint16_t raw_len() const;
+ uint8_t hlen() const;
+ uint8_t ver() const;
private:
sfip_t src;
sfip_t dst;
- const sfip_t* src_p;
- const sfip_t* dst_p;
- const IP4Hdr* ip4h;
- const IP6Hdr* ip6h;
+ const void* iph;
+ Type type;
};
-inline bool operator==(const IpApi& lhs, const IpApi& rhs)
-{ return (lhs.ip4h == rhs.ip4h) && (lhs.ip6h == rhs.ip6h); }
-
-inline bool operator!=(const IpApi& lhs, const IpApi& rhs)
-{ return !(lhs == rhs); }
} // namespace ip
#endif
/* Boolean functions - general information about this packet */
inline bool has_ip() const
- { return ptrs.ip_api.is_valid(); }
+ { return ptrs.ip_api.is_ip(); }
inline bool is_ip4() const
{ return ptrs.ip_api.is_ip4(); }
memset(&flow, '\0', offsetof(Packet, pkth));
ptrs.reset();
}
+ bool from_client()
+ { return (packet_flags & PKT_FROM_CLIENT) != 0; }
+
+ bool from_server()
+ { return (packet_flags & PKT_FROM_SERVER) != 0; }
+
+ bool is_portscan()
+ { return is_cooked() and (pseudo_type == PSEUDO_PKT_PS); }
+
+ bool is_full_pdu()
+ { return (packet_flags & PKT_PDU_FULL) == PKT_PDU_FULL; }
+
+ bool is_pdu_start()
+ { return (packet_flags & PKT_PDU_HEAD) != 0; }
+
+ bool has_paf_payload()
+ { return (packet_flags & PKT_REBUILT_STREAM) or is_full_pdu(); }
+
+ bool is_rebuilt()
+ { return (packet_flags & (PKT_REBUILT_STREAM|PKT_REBUILT_FRAG)) != 0; }
};
#define PKT_ZERO_LEN offsetof(Packet, pkth)
#define BIT(i) (0x1 << (i-1))
-static inline int PacketWasCooked(const Packet* const p)
-{ return ( p->packet_flags & PKT_PSEUDO ) != 0; }
-
-static inline bool IsPortscanPacket(const Packet* const p)
-{ return ( PacketWasCooked(p) && (p->pseudo_type == PSEUDO_PKT_PS)); }
-
-static inline bool PacketHasFullPDU(const Packet* const p)
-{ return ( (p->packet_flags & PKT_PDU_FULL) == PKT_PDU_FULL ); }
-
-static inline bool PacketHasStartOfPDU(const Packet* const p)
-{ return ( (p->packet_flags & PKT_PDU_HEAD) != 0 ); }
-
-static inline bool PacketHasPAFPayload(const Packet* const p)
-{ return ( (p->packet_flags & PKT_REBUILT_STREAM) || PacketHasFullPDU(p) ); }
-
-static inline bool PacketIsRebuilt(const Packet* const p)
-{ return ( (p->packet_flags & (PKT_REBUILT_STREAM|PKT_REBUILT_FRAG)) != 0 ); }
-
static inline void SetExtraData(Packet* p, const uint32_t xid)
{ p->xtradata_mask |= BIT(xid); }
"If this is an encapsulated layer, you must also set UNSURE_ENCAP"
" and SAVE_LAYER");
+RawData::RawData(const DAQ_PktHdr_t* h, const uint8_t* p)
+{
+ pkth = h;
+ data = p;
+ len = h->caplen;
+}
+
//-------------------------------------------------------------------------
// Encode/Decode functions
//-------------------------------------------------------------------------
uint16_t prev_prot_id = FINISHED_DECODE;
uint8_t mapped_prot = CodecManager::grinder;
- RawData raw;
- raw.data = pkt;
- raw.len = pkthdr->caplen;
+ RawData raw(pkthdr, pkt);
CodecData codec_data(FINISHED_DECODE);
if ( cooked )
{
char dir;
uint8_t ttl;
- const bool outer = p->ptrs.ip_api.is_valid();
+ const bool outer = p->ptrs.ip_api.is_ip();
if ( !p->flow )
return 0;
//--------------------------------------------------------------------------
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2002-2013 Sourcefire, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
* An abstracted interface to the Multi-Pattern Matching routines,
* thats why we're passing 'void *' objects around.
*
-* Copyright (C) 2002-2013 Sourcefire, Inc.
* Marc A Norton <mnorton@sourcefire.com>
*
* Updates:
//--------------------------------------------------------------------------
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2002-2013 Sourcefire, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
* An abstracted interface to the Multi-Pattern Matching routines,
* thats why we're passing 'void *' objects around.
*
-* Copyright (C) 2002-2013 Sourcefire, Inc.
* Marc A Norton <mnorton@sourcefire.com>
*
* Updates:
** Reference - Efficient String matching: An Aid to Bibliographic Search
** Alfred V Aho and Margaret J Corasick
** Bell Labratories
-** Copyright(C) 1975 Association for Computing Machinery,Inc
+** Copyright (C) 1975 Association for Computing Machinery,Inc
**
** Implemented from the 4 algorithms in the paper by Aho & Corasick
** and some implementation ideas from 'Practical Algorithms in C'
//--------------------------------------------------------------------------
-// Copyright(C) 2002,2003,2004 Marc Norton
-// Copyright(C) 2003,2004 Daniel Roelker
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
// Copyright (C) 2002-2013 Sourcefire, Inc.
+// Copyright (C) 2003-2004 Daniel Roelker
+// Copyright (C) 2002-2004 Marc Norton
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
** Reference - Efficient String matching: An Aid to Bibliographic Search
** Alfred V Aho and Margaret J Corasick
** Bell Labratories
-** Copyright(C) 1975 Association for Computing Machinery,Inc
+** Copyright (C) 1975 Association for Computing Machinery,Inc
**
** +++
** +++ Version 1.0 notes - Marc Norton:
** Reference - Efficient String matching: An Aid to Bibliographic Search
** Alfred V Aho and Margaret J Corasick
** Bell Labratories
-** Copyright(C) 1975 Association for Computing Machinery,Inc
+** Copyright (C) 1975 Association for Computing Machinery,Inc
**
** 12/4/06 - man - modified summary
** 6/26/07 - man - Added last_match tracking, and accounted for nocase/case by
static inline int InspectClientPacket(Packet* p)
{
- return PacketHasPAFPayload(p);
+ return p->has_paf_payload();
}
static int SnortFTP(
result = stream.set_application_protocol_id_expected(
&session->clientIP, session->clientPort,
&session->serverIP, session->serverPort,
- p->get_ip_proto_next(), ftp_data_app_id, fd);
+ p->type(), ftp_data_app_id, fd);
if (result < 0)
delete fd;
stream.ignore_session(
&session->clientIP, session->clientPort,
&session->serverIP, session->serverPort,
- p->get_ip_proto_next(), FtpDataFlowData::flow_id,
+ p->type(), FtpDataFlowData::flow_id,
SSN_DIR_BOTH);
}
}
result = stream.set_application_protocol_id_expected(
&session->clientIP, session->clientPort,
&session->serverIP, session->serverPort,
- p->get_ip_proto_next(), ftp_data_app_id, fd);
+ p->type(), ftp_data_app_id, fd);
if (result < 0)
delete fd;
stream.ignore_session(
&session->clientIP, session->clientPort,
&session->serverIP, session->serverPort,
- p->get_ip_proto_next(), FtpDataFlowData::flow_id,
+ p->type(), FtpDataFlowData::flow_id,
SSN_DIR_BOTH);
}
}
{
{
/* Might have gotten non-ascii characters, hence no method, but if
- * PAF is in use, checking "!stream_ins" equates to PacketHasStartOfPDU()
+ * PAF is in use, checking "!stream_ins" equates to is_pdu_start()
* so we know we're looking for a method and not guessing that we're in
* the body or somewhere else because we found a non-ascii character */
if ( !stream_ins )
{
FilePosition position = SNORT_FILE_POSITION_UNKNOWN;
- if (PacketHasFullPDU(p))
+ if (p->is_full_pdu())
position = SNORT_FILE_FULL;
- else if (PacketHasStartOfPDU(p))
+ else if (p->is_pdu_start())
position = SNORT_FILE_START;
else if (p->packet_flags & PKT_PDU_TAIL)
position = SNORT_FILE_END;
hsd = get_session_data(p->flow);
- if ( (p->packet_flags & PKT_STREAM_INSERT) &&
- !PacketHasFullPDU(p) )
+ if ( (p->packet_flags & PKT_STREAM_INSERT) && !p->is_full_pdu() )
{
int flow_depth;
set_file_data((uint8_t*)session->server.response.body, detect_data_size);
}
- if (PacketHasPAFPayload(p)
+ if (p->has_paf_payload()
&& file_api->file_process(p,(uint8_t*)session->server.response.body,
(uint16_t)session->server.response.body_size,
getFilePoistion(p), false, false))
*/
if (iInspectMode == HI_SI_CLIENT_MODE)
{
- iRet = hi_client_inspection(p, (void*)session, hsd, !PacketHasStartOfPDU(p));
+ iRet = hi_client_inspection(p, (void*)session, hsd, !p->is_pdu_start());
if (iRet)
return iRet;
seq_num = GET_PKT_SEQ(p);
{
- expected_pkt = !PacketHasStartOfPDU(p);
+ expected_pkt = !p->is_pdu_start();
parse_cont_encoding = !expected_pkt;
- not_stream_insert = PacketHasPAFPayload(p);
+ not_stream_insert = p->has_paf_payload();
if ( !expected_pkt )
{
if (p->packet_flags & PKT_STREAM_INSERT)
{
- if ( PacketHasFullPDU(p) )
+ if ( p->is_full_pdu() )
expected_pkt = 1;
else
sd->resp_state.inspect_reassembled = 1;
PROFILE_VARS;
// preconditions - what we registered for
- assert(p->is_tcp() && p->dsize && p->data);
+ // FIXIT remove proto check? check for tcp or user?
+ //assert(p->is_tcp() && p->dsize && p->data);
+ assert(p->dsize && p->data);
MODULE_PROFILE_START(hiPerfStats);
hi_clear_events();
static inline int InspectPacket(Packet* p)
{
- return PacketHasPAFPayload(p);
+ return p->has_paf_payload();
}
static int IMAP_Setup(Packet* p, IMAPData* ssn)
static inline int InspectPacket(Packet* p)
{
- return PacketHasPAFPayload(p);
+ return p->has_paf_payload();
}
static int POP_Setup(Packet* p, POPData* ssn)
smtp_config.h
smtp_module.cc
smtp_module.h
+ smtp_normalize.cc
+ smtp_normalize.h
)
if (STATIC_INSPECTORS)
static inline int InspectPacket(Packet* p)
{
- return PacketHasPAFPayload(p);
+ return p->has_paf_payload();
}
/*
#include "wiz_module.h"
#include "flow/flow.h"
#include "framework/inspector.h"
-#include "stream/stream_splitter.h"
#include "managers/inspector_manager.h"
#include "protocols/packet.h"
-#include "stream/stream_api.h"
#include "stream/stream_splitter.h"
#include "time/profiler.h"
#include "utils/stats.h"
PegCount tcp_hits;
PegCount udp_scans;
PegCount udp_hits;
+ PegCount user_scans;
+ PegCount user_hits;
};
const PegInfo wiz_pegs[] =
{ "tcp hits", "tcp identifications" },
{ "udp scans", "udp payload scans" },
{ "udp hits", "udp identifications" },
+ { "user scans", "user payload scans" },
+ { "user hits", "user identifications" },
{ nullptr, nullptr }
};
mod_dtor
},
IT_WIZARD,
- (uint16_t)PktType::TCP | (uint16_t)PktType::UDP,
+ (uint16_t)PktType::TCP | (uint16_t)PktType::UDP | (uint16_t)PktType::USER,
nullptr, // buffers
nullptr, // service
nullptr, // init
add_subdirectory(icmp)
add_subdirectory(tcp)
add_subdirectory(udp)
+add_subdirectory(user)
+add_subdirectory(file)
set (STREAM_INCLUDES
+ paf.h
stream_api.h
stream_splitter.h
)
add_library( stream STATIC
flush_bucket.cc
flush_bucket.h
+ paf.cc
stream.h
stream_api.cc
stream_inspectors.cc
stream_icmp
stream_tcp
stream_udp
+ stream_user
+ stream_file
protocols
)
x_includedir = $(pkgincludedir)/stream
x_include_HEADERS = \
+paf.h \
stream_api.h \
stream_splitter.h
libstream_a_SOURCES = \
flush_bucket.cc \
flush_bucket.h \
+paf.cc \
stream.h \
stream_api.cc \
stream_inspectors.cc \
#icmp/libstream_icmp.a
#tcp/libstream_tcp.a
#udp/libstream_udp.a
+#user/libstream_user.a
+#file/libstream_file.a
SUBDIRS = \
base \
ip \
icmp \
tcp \
-udp
+udp \
+user \
+file
AM_CXXFLAGS = @AM_CXXFLAGS@
struct BaseStats
{
+ PegCount ip_flows;
+ PegCount ip_prunes;
+
+ PegCount icmp_flows;
+ PegCount icmp_prunes;
+
PegCount tcp_flows;
PegCount tcp_prunes;
PegCount udp_flows;
PegCount udp_prunes;
- PegCount icmp_flows;
- PegCount icmp_prunes;
+ PegCount user_flows;
+ PegCount user_prunes;
- PegCount ip_flows;
- PegCount ip_prunes;
+ PegCount file_flows;
+ PegCount file_prunes;
};
static BaseStats g_stats;
const PegInfo base_pegs[] =
{
+ { "ip flows", "total ip sessions" },
+ { "ip prunes", "ip sessions pruned" },
+ { "icmp flows", "total icmp sessions" },
+ { "icmp prunes", "icmp sessions pruned" },
{ "tcp flows", "total tcp sessions" },
{ "tcp prunes", "tcp sessions pruned" },
{ "udp flows", "total udp sessions" },
{ "udp prunes", "udp sessions pruned" },
- { "icmp flows", "total icmp sessions" },
- { "icmp prunes", "icmp sessions pruned" },
- { "ip flows", "total ip sessions" },
- { "ip prunes", "ip sessions pruned" },
+ { "user flows", "total user sessions" },
+ { "user prunes", "user sessions pruned" },
+ { "file flows", "total file sessions" },
+ { "file prunes", "file sessions pruned" },
{ nullptr, nullptr }
};
if ( !flow_con )
return;
- t_stats.tcp_flows = flow_con->get_flows(IPPROTO_TCP);
- t_stats.tcp_prunes = flow_con->get_prunes(IPPROTO_TCP);
+ t_stats.ip_flows = flow_con->get_flows(PktType::IP);
+ t_stats.ip_prunes = flow_con->get_prunes(PktType::IP);
- t_stats.udp_flows = flow_con->get_flows(IPPROTO_UDP);
- t_stats.udp_prunes = flow_con->get_prunes(IPPROTO_UDP);
+ t_stats.icmp_flows = flow_con->get_flows(PktType::ICMP);
+ t_stats.icmp_prunes = flow_con->get_prunes(PktType::ICMP);
- t_stats.icmp_flows = flow_con->get_flows(IPPROTO_ICMP);
- t_stats.icmp_prunes = flow_con->get_prunes(IPPROTO_ICMP);
+ t_stats.tcp_flows = flow_con->get_flows(PktType::TCP);
+ t_stats.tcp_prunes = flow_con->get_prunes(PktType::TCP);
- t_stats.ip_flows = flow_con->get_flows(IPPROTO_IP);
- t_stats.ip_prunes = flow_con->get_prunes(IPPROTO_IP);
+ t_stats.udp_flows = flow_con->get_flows(PktType::UDP);
+ t_stats.udp_prunes = flow_con->get_prunes(PktType::UDP);
+
+ t_stats.user_flows = flow_con->get_flows(PktType::USER);
+ t_stats.user_prunes = flow_con->get_prunes(PktType::USER);
+
+ t_stats.file_flows = flow_con->get_flows(PktType::FILE);
+ t_stats.file_prunes = flow_con->get_prunes(PktType::FILE);
sum_stats((PegCount*)&g_stats, (PegCount*)&t_stats,
array_size(base_pegs)-1);
flow_con = new FlowControl;
InspectSsnFunc f;
+ if ( config->ip_cfg.max_sessions )
+ {
+ if ( (f = InspectorManager::get_session((uint16_t)PktType::IP)) )
+ flow_con->init_ip(config->ip_cfg, f);
+ }
+ if ( config->icmp_cfg.max_sessions )
+ {
+ if ( (f = InspectorManager::get_session((uint16_t)PktType::ICMP)) )
+ flow_con->init_icmp(config->icmp_cfg, f);
+ }
if ( config->tcp_cfg.max_sessions )
{
if ( (f = InspectorManager::get_session((uint16_t)PktType::TCP)) )
if ( (f = InspectorManager::get_session((uint16_t)PktType::UDP)) )
flow_con->init_udp(config->udp_cfg, f);
}
- if ( config->ip_cfg.max_sessions )
- {
- if ( (f = InspectorManager::get_session((uint16_t)PktType::IP)) )
- flow_con->init_ip(config->ip_cfg, f);
- }
- if ( config->icmp_cfg.max_sessions )
+ if ( config->user_cfg.max_sessions )
{
- if ( (f = InspectorManager::get_session((uint16_t)PktType::ICMP)) )
- flow_con->init_icmp(config->icmp_cfg, f);
+ if ( (f = InspectorManager::get_session((uint16_t)PktType::USER)) )
+ flow_con->init_user(config->user_cfg, f);
}
- if ( config->tcp_cfg.max_sessions || config->udp_cfg.max_sessions )
+ if ( config->file_cfg.max_sessions )
{
- flow_con->init_exp(config->tcp_cfg, config->udp_cfg);
+ if ( (f = InspectorManager::get_session((uint16_t)PktType::FILE)) )
+ flow_con->init_file(config->file_cfg, f);
}
+ uint32_t max = config->tcp_cfg.max_sessions + config->udp_cfg.max_sessions
+ + config->user_cfg.max_sessions;
+
+ if ( max > 0 )
+ flow_con->init_exp(max);
}
void StreamBase::tterm()
{
- flow_con->purge_flows(IPPROTO_TCP);
- flow_con->purge_flows(IPPROTO_UDP);
- flow_con->purge_flows(IPPROTO_ICMP);
- flow_con->purge_flows(IPPROTO_IP);
+ flow_con->purge_flows(PktType::IP);
+ flow_con->purge_flows(PktType::ICMP);
+ flow_con->purge_flows(PktType::TCP);
+ flow_con->purge_flows(PktType::UDP);
+ flow_con->purge_flows(PktType::USER);
+ flow_con->purge_flows(PktType::FILE);
}
void StreamBase::show(SnortConfig*)
switch ( p->type() )
{
+ case PktType::IP:
+ if ( p->has_ip() )
+ flow_con->process_ip(p);
+ break;
+
+ case PktType::ICMP:
+ if ( p->ptrs.icmph )
+ flow_con->process_icmp(p);
+ break;
+
case PktType::TCP:
if ( p->ptrs.tcph )
flow_con->process_tcp(p);
flow_con->process_udp(p);
break;
- case PktType::ICMP:
- if ( p->ptrs.icmph )
- flow_con->process_icmp(p);
+ case PktType::USER:
+ flow_con->process_user(p);
break;
- case PktType::IP:
- if ( p->has_ip() )
- flow_con->process_ip(p);
+ case PktType::FILE:
+ flow_con->process_file(p);
break;
default:
mod_dtor
},
IT_STREAM,
- (unsigned)PktType::ANY_IP,
+ (unsigned)PktType::ANY_SSN,
nullptr, // buffers
nullptr, // service
nullptr, // init
{ 8*K, 32*K, 30, 180 }, // icmp
{ 8*K, 128*K, 30, 180 }, // tcp
{ 8*K, 64*K, 30, 180 }, // udp
+ { 8*K, 8*K, 30, 180 }, // user
+ { 8*K, 4*K, 30, 180 }, // file
};
//-------------------------------------------------------------------------
FlowConfig icmp_cfg;
FlowConfig tcp_cfg;
FlowConfig udp_cfg;
+ FlowConfig user_cfg;
+ FlowConfig file_cfg;
};
class StreamModule : public Module
--- /dev/null
+
+add_library( stream_file STATIC
+ file_module.cc
+ file_module.h
+ file_session.cc
+ file_session.h
+ stream_file.cc
+ stream_file.h
+)
--- /dev/null
+AUTOMAKE_OPTIONS=foreign no-dependencies
+
+noinst_LIBRARIES = libstream_file.a
+
+libstream_file_a_SOURCES = \
+file_module.cc \
+file_module.h \
+file_session.cc \
+file_session.h \
+stream_file.cc \
+stream_file.h
+
+AM_CXXFLAGS = @AM_CXXFLAGS@
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// file_module.cc author Russ Combs <rucombs@cisco.com>
+
+#include "file_module.h"
+
+#include <string>
+using namespace std;
+
+#include "stream_file.h"
+#include "main/snort_config.h"
+#include "stream/stream.h"
+
+//-------------------------------------------------------------------------
+// stream_file module
+//-------------------------------------------------------------------------
+
+static const Parameter s_params[] =
+{
+ { "upload", Parameter::PT_BOOL, nullptr, "false",
+ "indicate file transfer direction" },
+
+ { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+StreamFileModule::StreamFileModule() :
+ Module(MOD_NAME, MOD_HELP, s_params) { }
+
+StreamFileModule::~StreamFileModule() { }
+
+#if 0
+const PegInfo* StreamFileModule::get_pegs() const
+{ return file_pegs; }
+
+PegCount* StreamFileModule::get_counts() const
+{ return (PegCount*)&file_stats; }
+#endif
+
+bool StreamFileModule::begin(const char*, int, SnortConfig*)
+{
+ upload = false;
+ return true;
+}
+
+bool StreamFileModule::set(const char*, Value& v, SnortConfig*)
+{
+ if ( v.is("upload") )
+ upload = v.get_bool();
+
+ else
+ return false;
+
+ return true;
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// file_module.h author Russ Combs <rucombs@cisco.com>
+
+#ifndef FILE_MODULE_H
+#define FILE_MODULE_H
+
+#include "snort_types.h"
+#include "framework/module.h"
+#include "main/thread.h"
+#include "stream/stream.h"
+
+struct SnortConfig;
+
+extern const PegInfo file_pegs[];
+extern THREAD_LOCAL struct FileStats file_stats;
+extern THREAD_LOCAL ProfileStats file_perf_stats;
+
+//-------------------------------------------------------------------------
+// stream_file module
+//-------------------------------------------------------------------------
+
+#define MOD_NAME "stream_file"
+#define MOD_HELP "stream inspector for file flow tracking and processing"
+
+class StreamFileModule : public Module
+{
+public:
+ StreamFileModule();
+ ~StreamFileModule();
+
+#if 0
+ const PegInfo* get_pegs() const override;
+ PegCount* get_counts() const override;
+#endif
+
+ bool begin(const char*, int, SnortConfig*) override;
+ bool set(const char*, Value&, SnortConfig*) override;
+
+ bool upload;
+};
+
+#endif
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// file_session.cc author Russ Combs <rucombs@cisco.com>
+
+#include "file_session.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "stream_file.h"
+#include "file_module.h"
+#include "file_api/file_api.h"
+#include "perf_monitor/perf.h"
+#include "time/profiler.h"
+#include "packet_io/sfdaq.h"
+#include "detection/detection_util.h"
+
+#define DECODE_PDU (DECODE_SOF | DECODE_EOF)
+
+THREAD_LOCAL ProfileStats file_ssn_stats;
+
+//-------------------------------------------------------------------------
+// FileSession methods
+//-------------------------------------------------------------------------
+
+FileSession::FileSession(Flow* flow) : Session(flow) { }
+
+FileSession::~FileSession() { }
+
+bool FileSession::setup(Packet*)
+{
+ // FIXIT file context is null here
+ //const char* s = DAQ_GetInterfaceSpec();
+ //file_api->set_file_name(p->flow, (uint8_t*)s, strlen(s));
+ return true;
+}
+
+void FileSession::clear() { }
+
+static FilePosition position(Packet* p)
+{
+ if ( (p->ptrs.decode_flags & DECODE_PDU) == DECODE_PDU )
+ return SNORT_FILE_FULL;
+
+ if ( p->ptrs.decode_flags & DECODE_SOF )
+ return SNORT_FILE_START;
+
+ if ( p->ptrs.decode_flags & DECODE_EOF )
+ return SNORT_FILE_END;
+
+ return SNORT_FILE_MIDDLE;
+}
+
+int FileSession::process(Packet* p)
+{
+ PROFILE_VARS;
+ MODULE_PROFILE_START(file_ssn_stats);
+
+ StreamFileConfig* c = get_file_cfg(p->flow->ssn_server);
+ file_api->file_process(p, (uint8_t*)p->data, p->dsize, position(p), c->upload, false);
+ set_file_data((uint8_t*)p->data, p->dsize);
+
+ MODULE_PROFILE_END(file_ssn_stats);
+ return 0;
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// file_session.h author Russ Combs <rucombs@cisco.com>
+
+#ifndef USER_SESSION_H
+#define USER_SESSION_H
+
+#include <assert.h>
+#include <list>
+
+#include "flow/session.h"
+#include "stream/paf.h"
+
+class FileSession : public Session
+{
+public:
+ FileSession(Flow*);
+ ~FileSession();
+
+ bool setup(Packet*) override;
+ void clear() override;
+ int process(Packet*) override;
+
+ bool is_sequenced(uint8_t /*dir*/) override
+ { return true; }
+
+ bool are_packets_missing(uint8_t /*dir*/) override
+ { return false; }
+
+ uint8_t missing_in_reassembled(uint8_t /*dir*/) override
+ { return SSN_MISSING_NONE; }
+
+private:
+ void start(Packet*, Flow*);
+ void update(Packet*, Flow*);
+ void end(Packet*, Flow*);
+};
+
+#endif
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// stream_file.cc author Russ Combs <rucombs@cisco.com>
+
+#include "stream_file.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <assert.h>
+
+#include "file_module.h"
+#include "file_session.h"
+#include "log/messages.h"
+#include "protocols/packet.h"
+
+//-------------------------------------------------------------------------
+// inspector stuff
+//-------------------------------------------------------------------------
+
+class StreamFile : public Inspector
+{
+public:
+ StreamFile(bool b)
+ { config.upload = b; }
+
+ void eval(Packet*) override;
+
+ StreamFileConfig config;
+};
+
+void StreamFile::eval(Packet*)
+{
+ // session::process() instead
+ assert(false);
+}
+
+StreamFileConfig* get_file_cfg(Inspector* ins)
+{
+ assert(ins);
+ return &((StreamFile*)ins)->config;
+}
+
+//-------------------------------------------------------------------------
+// api stuff
+//-------------------------------------------------------------------------
+
+static Module* mod_ctor()
+{ return new StreamFileModule; }
+
+static void mod_dtor(Module* m)
+{ delete m; }
+
+static Inspector* file_ctor(Module* m)
+{
+ StreamFileModule* mod = (StreamFileModule*)m;
+ return new StreamFile(mod->upload);
+}
+
+static void file_dtor(Inspector* p)
+{
+ delete p;
+}
+
+static Session* file_ssn(Flow* lws)
+{
+ return new FileSession(lws);
+}
+
+static const InspectApi sfile_api =
+{
+ {
+ PT_INSPECTOR,
+ sizeof(InspectApi),
+ INSAPI_VERSION,
+ 0,
+ API_RESERVED,
+ API_OPTIONS,
+ MOD_NAME,
+ MOD_HELP,
+ mod_ctor,
+ mod_dtor
+ },
+ IT_STREAM,
+ (unsigned)PktType::FILE,
+ nullptr, // buffers
+ nullptr, // service
+ nullptr, // pinit
+ nullptr, // pterm
+ nullptr, // tinit
+ nullptr, // tterm
+ file_ctor,
+ file_dtor,
+ file_ssn,
+ nullptr // reset
+};
+
+const BaseApi* nin_stream_file = &sfile_api.base;
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// stream_file.h author Russ Combs <rucombs@cisco.com>
+
+#ifndef STREAM_FILE_H
+#define STREAM_FILE_H
+
+struct StreamFileConfig
+{
+ bool upload;
+};
+
+StreamFileConfig* get_file_cfg(class Inspector*);
+
+#endif
{
if (mem_in_use > FRAG_MEMCAP)
{
- flow_con->prune_flows(IPPROTO_IP, p);
+ flow_con->prune_flows(PktType::IP, p);
}
f = (Fragment*)SnortAlloc(sizeof(Fragment));
{
if (mem_in_use > FRAG_MEMCAP)
{
- flow_con->prune_flows(IPPROTO_IP, p);
+ flow_con->prune_flows(PktType::IP, p);
}
/*
{
if (mem_in_use > FRAG_MEMCAP)
{
- flow_con->prune_flows(IPPROTO_IP, p);
+ flow_con->prune_flows(PktType::IP, p);
}
/*
// private methods
//-------------------------------------------------------------------------
-void IpSessionCleanup(Flow* lws, FragTracker* tracker)
+static void IpSessionCleanup (Flow* lws, FragTracker* tracker)
{
if ( lws->ssn_server )
{
IpSessionCleanup(flow, &tracker);
}
-bool IpSession::setup(Packet* p)
+bool IpSession::setup(Packet*)
{
DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
"Stream IP session created!\n"); );
memset(&tracker, 0, sizeof(tracker));
// FIXIT count ip session creates here
- sfip_copy(flow->client_ip, p->ptrs.ip_api.get_src());
- sfip_copy(flow->server_ip, p->ptrs.ip_api.get_dst());
-
#ifdef ENABLE_EXPECTED_IP
if ( flow_con->expected_session(flow, p))
{
if ( stream.expired_session(flow, p) )
{
IpSessionCleanup(flow, &tracker);
- // FIXIT count ip sessiont imeouts here
+ // FIXIT count ip session timeouts here
#ifdef ENABLE_EXPECTED_IP
if ( flow_con->expected_session(flow, p))
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//--------------------------------------------------------------------------
-//--------------------------------------------------------------------
-// s5 stuff
-//
-// @file stream_paf.c
-// @author Russ Combs <rcombs@sourcefire.com>
-//--------------------------------------------------------------------
+// paf.cc author Russ Combs <rcombs@sourcefire.com>
-#include "stream_paf.h"
+#include "paf.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
static THREAD_LOCAL uint64_t prep_bytes = 0;
// s5_len and s5_idx are used only during the
-// lifetime of s5_paf_check()
+// lifetime of paf_check()
// FIXIT-L these thread local should be moved into thread context
static THREAD_LOCAL uint32_t s5_len; // total bytes queued
static THREAD_LOCAL uint32_t s5_idx; // offset from start of queued bytes
//--------------------------------------------------------------------
-static int32_t s5_paf_flush(
+static uint32_t paf_flush (
StreamSplitter*, PAF_State* ps, FlushType ft, uint32_t* flags)
{
uint32_t at = 0;
//--------------------------------------------------------------------
-static bool s5_paf_callback(
+static bool paf_callback (
StreamSplitter* ss, PAF_State* ps, Flow* ssn,
const uint8_t* data, uint32_t len, uint32_t flags)
{
//--------------------------------------------------------------------
-static inline bool s5_paf_eval(
+static inline bool paf_eval (
StreamSplitter* ss, PAF_State* ps, Flow* ssn,
uint32_t flags, const uint8_t* data, uint32_t len, FlushType* ft)
{
case StreamSplitter::SEARCH:
if ( s5_len > s5_idx )
{
- return s5_paf_callback(ss, ps, ssn, data, len, flags);
+ return paf_callback(ss, ps, ssn, data, len, flags);
}
return false;
len -= delta;
}
s5_idx = ps->fpt;
- return s5_paf_callback(ss, ps, ssn, data, len, flags);
+ return paf_callback(ss, ps, ssn, data, len, flags);
}
return false;
case StreamSplitter::LIMITED:
- // increment position by previously scanned bytes. set in s5_paf_flush
+ // increment position by previously scanned bytes. set in paf_flush
ps->paf = StreamSplitter::SEARCH;
s5_idx += ps->fpt;
ps->fpt = 0;
// public stuff
//--------------------------------------------------------------------
-void s5_paf_setup(PAF_State* ps)
+void paf_setup (PAF_State* ps)
{
// this is already cleared when instantiated
//memset(ps, 0, sizeof(*ps));
ps->paf = StreamSplitter::START;
}
-void s5_paf_clear(PAF_State* ps)
+void paf_clear (PAF_State* ps)
{
ps->paf = StreamSplitter::ABORT;
}
//--------------------------------------------------------------------
-int32_t s5_paf_check(
+uint32_t paf_check (
StreamSplitter* ss, PAF_State* ps, Flow* ssn,
const uint8_t* data, uint32_t len, uint32_t total,
uint32_t seq, uint32_t* flags)
"%s: len=%u, amt=%u, seq=%u, cur=%u, pos=%u, fpt=%u, tot=%u, paf=%d\n",
__FUNCTION__, len, total, seq, ps->seq, ps->pos, ps->fpt, ps->tot, ps->paf); )
- if ( !s5_paf_initialized(ps) )
+ if ( !paf_initialized(ps) )
{
ps->seq = ps->pos = seq;
ps->paf = StreamSplitter::SEARCH;
if (s5_len)
{
ps->fpt = 0;
- return s5_paf_flush(ss, ps, FT_MAX, flags);
+ return paf_flush(ss, ps, FT_MAX, flags);
}
*flags = 0;
return -1;
// occurs at the paf_max byte. So, we manually set the data's length and
// total queued bytes (s5_len) to guarantee that at most paf_max bytes will
// be analyzed and flushed since the last flush point. It should also be
- // noted that we perform the check here rather in in s5_paf_flush() to
- // avoid scanning the same data twice. The first scan would analyze the
+ // noted that we perform the check here rather in in paf_flush() to
+ // avoid scanning the same data twice. The first scan would analyze the
// entire segment and the second scan would analyze this segments
// unflushed data.
uint16_t fuzz = 0; // FIXIT-L PAF add a little zippedy-do-dah
uint32_t shift;
int32_t fp;
- bool cont = s5_paf_eval(ss, ps, ssn, *flags, data, len, &ft);
+ bool cont = paf_eval(ss, ps, ssn, *flags, data, len, &ft);
if ( ft != FT_NOP )
{
- fp = s5_paf_flush(ss, ps, ft, flags);
- if ( fp > 0 )
- s5_paf_jump(ps, fp);
- else
- s5_paf_jump(ps, 0);
+ fp = paf_flush(ss, ps, ft, flags);
+ paf_jump(ps, fp);
return fp;
}
if ( !cont )
if ( (ps->paf != StreamSplitter::FLUSH) && (s5_len > ss->max(ssn)+fuzz) )
{
- int32_t fp = s5_paf_flush(ss, ps, FT_MAX, flags);
- if ( fp > 0 )
- s5_paf_jump(ps, fp);
- else
- s5_paf_jump(ps, 0);
+ uint32_t fp = paf_flush(ss, ps, FT_MAX, flags);
+ paf_jump(ps, fp);
return fp;
}
return -1;
//--------------------------------------------------------------------------
//--------------------------------------------------------------------
-// s5 protocol aware flushing stuff
-//
-// @file stream_paf.h
-// @author Russ Combs <rcombs@sourcefire.com>
+// protocol aware flushing stuff
+// paf.h author Russ Combs <rcombs@sourcefire.com>
//--------------------------------------------------------------------
-#ifndef STREAM_PAF_H
-#define STREAM_PAF_H
+#ifndef PAF_H
+#define PAF_H
#include <stdint.h>
#include "snort_types.h"
struct SnortConfig;
-void* s5_paf_new(unsigned max); // create new paf config (per policy)
-void s5_paf_delete(void*); // free config
+void* paf_new(unsigned max); // create new paf config (per policy)
+void paf_delete(void*); // free config
struct PAF_State // per session direction
{
StreamSplitter::Status paf; // current scan state
};
-void s5_paf_setup(PAF_State*); // called at session start
-void s5_paf_clear(PAF_State*); // called at session end
+void paf_setup(PAF_State*); // called at session start
+void paf_clear(PAF_State*); // called at session end
-static inline uint32_t s5_paf_position(PAF_State* ps)
+static inline uint32_t paf_position (PAF_State* ps)
{
return ps->seq;
}
-static inline uint32_t s5_paf_initialized(PAF_State* ps)
+static inline uint32_t paf_initialized (PAF_State* ps)
{
return ( ps->paf != StreamSplitter::START );
}
-static inline uint32_t s5_paf_active(PAF_State* ps)
+static inline uint32_t paf_active (PAF_State* ps)
{
return ( ps->paf != StreamSplitter::ABORT );
}
-static inline void s5_paf_jump(PAF_State* ps, uint32_t n)
+static inline void paf_jump(PAF_State* ps, uint32_t n)
{
ps->pos += n;
ps->seq = ps->pos;
}
-// called on each in order segment:
-// -- returns -1 for no flush
-// -- returns 0 to flush all data prior to this buffer
-// -- returns >0 to flush to offset from start of buffer
-int32_t s5_paf_check(
+// called on each in order segment
+uint32_t paf_check(
StreamSplitter* paf_config, PAF_State*, Flow* ssn,
const uint8_t* data, uint32_t len, uint32_t total,
uint32_t seq, uint32_t* flags);
#include "flow/flow_cache.h"
#include "flow/session.h"
#include "stream/stream.h"
-#include "tcp/stream_paf.h"
+#include "stream/paf.h"
#include "tcp/stream_tcp.h"
#include "udp/stream_udp.h"
#include "icmp/stream_icmp.h"
xtradata_func_count = 0;
extra_data_log = NULL;
extra_data_config = NULL;
+
+ // FIXIT-L this is a hack around gnus crappy linker:
+ // libstream.a is linked before the other stream libs to ensure that
+ // the plugin symbols are located. however, this causes the below paf
+ // functions to not be located. the only alternative to this hack
+ // appears to be breaking up the libs further to avoid the circularity.
+ // not a bad requirement in theory, but in practice a bit restrictive.
+ // links just fine on osx w/o this hack!
+ typedef void (*ugh)();
+ if ( (ugh)paf_setup == (ugh)paf_clear || (ugh)paf_clear == (ugh)paf_check )
+ printf("ugh! this check failed to ensure that gnus links finds paf setup/clear/check\n");
}
Stream::~Stream() { }
//-------------------------------------------------------------------------
Flow* Stream::get_session_ptr_from_ip_port(
- const sfip_t* srcIP, uint16_t srcPort,
- const sfip_t* dstIP, uint16_t dstPort,
- uint8_t ip_protocol, uint16_t vlan, uint32_t mplsId,
- uint16_t addressSpaceId)
+ uint8_t type, uint8_t proto,
+ const sfip_t *srcIP, uint16_t srcPort,
+ const sfip_t *dstIP, uint16_t dstPort,
+ uint16_t vlan, uint32_t mplsId, uint16_t addressSpaceId)
{
FlowKey key;
- key.init(srcIP, srcPort, dstIP, dstPort, ip_protocol, vlan, mplsId, addressSpaceId);
+ key.init(type, proto, srcIP, srcPort, dstIP, dstPort, vlan, mplsId, addressSpaceId);
return get_session(&key);
}
#endif
key->init(
+ (uint8_t)p->type(), p->get_ip_proto_next(),
p->ptrs.ip_api.get_src(), p->ptrs.sp,
p->ptrs.ip_api.get_dst(), p->ptrs.dp,
- p->get_ip_proto_next(),
// if the vlan protocol bit is defined, vlan layer gauranteed to exist
(p->proto_bits & PROTO_BIT__VLAN) ? layer::get_vlan_layer(p)->vid() : 0,
(p->proto_bits & PROTO_BIT__MPLS) ? p->ptrs.mplsHdr.label : 0,
}
FlowData* Stream::get_application_data_from_ip_port(
- const sfip_t* srcIP, uint16_t srcPort,
- const sfip_t* dstIP, uint16_t dstPort,
- uint8_t ip_protocol, uint16_t vlan, uint32_t mplsId,
+ uint8_t type, uint8_t proto,
+ const sfip_t *srcIP, uint16_t srcPort,
+ const sfip_t *dstIP, uint16_t dstPort,
+ uint16_t vlan, uint32_t mplsId,
uint16_t addressSpaceID, unsigned flow_id)
{
Flow* flow;
flow = get_session_ptr_from_ip_port(
+ type, proto,
srcIP, srcPort, dstIP, dstPort,
- ip_protocol, vlan, mplsId, addressSpaceID);
+ vlan, mplsId, addressSpaceID);
return flow->get_application_data(flow_id);
}
}
int Stream::ignore_session(
- const sfip_t* srcIP, uint16_t srcPort,
- const sfip_t* dstIP, uint16_t dstPort,
- uint8_t protocol, char direction,
+ const sfip_t *srcIP, uint16_t srcPort,
+ const sfip_t *dstIP, uint16_t dstPort,
+ PktType protocol, char direction,
uint32_t flow_id)
{
assert(flow_con);
Flow* flow, Packet* p, char dir,
int32_t /*bytes*/, int /*response*/)
{
- if (!flow)
- return;
+ assert(flow && flow->session);
switch (dir)
{
if (flow->protocol == PktType::TCP)
{
if (flow->ssn_state.ignore_direction & SSN_DIR_FROM_CLIENT)
- {
- StreamFlushClient(p, flow);
- }
+ flow->session->flush_client(p);
if (flow->ssn_state.ignore_direction & SSN_DIR_FROM_SERVER)
- {
- StreamFlushServer(p, flow);
- }
+ flow->session->flush_server(p);
}
/* TODO: Handle bytes/response parameters */
//-------------------------------------------------------------------------
int Stream::set_application_protocol_id_expected(
- const sfip_t* srcIP, uint16_t srcPort,
- const sfip_t* dstIP, uint16_t dstPort,
- uint8_t protocol, int16_t appId, FlowData* fd)
+ const sfip_t *srcIP, uint16_t srcPort,
+ const sfip_t *dstIP, uint16_t dstPort,
+ PktType protocol, int16_t appId, FlowData* fd)
{
assert(flow_con);
// splitter foo
//-------------------------------------------------------------------------
-bool Stream::is_paf_active(Flow* flow, bool to_server)
+void Stream::set_splitter(Flow* flow, bool to_server, StreamSplitter* ss)
{
- return StreamIsPafActiveTcp(flow, to_server);
+ assert(flow && flow->session);
+ return flow->session->set_splitter(to_server, ss);
}
-void Stream::set_splitter(Flow* flow, bool to_server, StreamSplitter* ss)
+StreamSplitter* Stream::get_splitter(Flow* flow, bool to_server)
{
- return StreamSetSplitterTcp(flow, to_server, ss);
+ assert(flow && flow->session);
+ return flow->session->get_splitter(to_server);
}
-StreamSplitter* Stream::get_splitter(Flow* flow, bool to_server)
+bool Stream::is_paf_active(Flow* flow, bool to_server)
{
- return StreamGetSplitterTcp(flow, to_server);
+ assert(flow && flow->session);
+ StreamSplitter* ss = flow->session->get_splitter(to_server);
+ return ss && ss->is_paf();
}
//-------------------------------------------------------------------------
static bool ok_to_flush(Packet* p)
{
- Flow* flow;
-
- if ((p == NULL) || (p->flow == NULL))
- {
- DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
- "Don't flush NULL packet or session\n"); );
+ if ( p->packet_flags & PKT_REBUILT_STREAM )
return false;
- }
-
- flow = p->flow;
- if ((flow->protocol != PktType::TCP) ||
- (p->packet_flags & PKT_REBUILT_STREAM))
- {
- DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
- "Don't flush on rebuilt packets\n"); );
+ if ( p->type() != PktType::TCP )
return false;
- }
+
return true;
}
/* Flush the listener queue -- this is the same side that
* the packet gets inserted into */
- StreamFlushListener(p, p->flow);
+ p->flow->session->flush_listener(p);
}
void Stream::flush_response(Packet* p)
/* Flush the talker queue -- this is the opposite side that
* the packet gets inserted into */
- StreamFlushTalker(p, p->flow);
+ p->flow->session->flush_talker(p);
}
// return true if added
uint32_t gid, uint32_t sid,
uint32_t event_id, uint32_t event_second)
{
- if ( !flow )
- return 0;
-
- /* Don't need to do this for other protos because they don't
- do any reassembly. */
- if ( p->type() != PktType::TCP )
- return 0;
-
- return StreamUpdateSessionAlertTcp(flow, p, gid, sid, event_id, event_second);
+ assert(flow && flow->session);
+ return flow->session->update_alert(p, gid, sid, event_id, event_second);
}
void Stream::set_extra_data(
- Flow* pv, Packet* p, uint32_t flag)
+ Flow* flow, Packet* p, uint32_t flag)
{
- Flow* flow = (Flow*)pv;
-
- if ( !flow )
- return;
-
- StreamSetExtraDataTcp(flow, p, flag);
+ assert(flow && flow->session);
+ flow->session->set_extra_data(p, flag);
}
// FIXIT-L get pv/flow from packet directly?
void Stream::clear_extra_data(
- Flow* pv, Packet* p, uint32_t flag)
+ Flow* flow, Packet* p, uint32_t flag)
{
- Flow* flow = (Flow*)pv;
-
- if ( !flow )
- return;
-
- StreamClearExtraDataTcp(flow, p, flag);
+ assert(flow && flow->session);
+ flow->session->clear_extra_data(p, flag);
}
int Stream::traverse_reassembled(
Packet* p, PacketIterator callback, void* userdata)
{
Flow* flow = p->flow;
-
- if (!flow || flow->protocol != PktType::TCP)
- return 0;
-
- /* Only if this is a rebuilt packet */
- if (!(p->packet_flags & PKT_REBUILT_STREAM))
- return 0;
-
- return GetTcpRebuiltPackets(p, flow, callback, userdata);
+ assert(flow && flow->session);
+ return flow->session->get_rebuilt_packets(p, callback, userdata);
}
int Stream::traverse_stream_segments(
Packet* p, StreamSegmentIterator callback, void* userdata)
{
Flow* flow = p->flow;
-
- if ((flow == NULL) || (flow->protocol != PktType::TCP))
- return -1;
-
- /* Only if this is a rebuilt packet */
- if (!(p->packet_flags & PKT_REBUILT_STREAM))
- return -1;
-
- return GetTcpStreamSegments(p, flow, callback, userdata);
+ assert(flow && flow->session);
+ return flow->session->get_segments(p, callback, userdata);
}
char Stream::get_reassembly_direction(Flow* flow)
{
- if (!flow || flow->protocol != PktType::TCP)
- return SSN_DIR_NONE;
-
- return StreamGetReassemblyDirectionTcp(flow);
+ assert(flow && flow->session);
+ return flow->session->get_reassembly_direction();
}
-char Stream::is_stream_sequenced(Flow* flow, char dir)
+bool Stream::is_stream_sequenced(Flow* flow, uint8_t dir)
{
- if (!flow || flow->protocol != PktType::TCP)
- return 1;
-
- return StreamIsStreamSequencedTcp(flow, dir);
+ assert(flow && flow->session);
+ return flow->session->is_sequenced(dir);
}
-int Stream::missing_in_reassembled(Flow* flow, char dir)
+int Stream::missing_in_reassembled(Flow* flow, uint8_t dir)
{
- if (!flow || flow->protocol != PktType::TCP)
- return SSN_MISSING_NONE;
-
- return StreamMissingInReassembledTcp(flow, dir);
+ assert(flow && flow->session);
+ return flow->session->missing_in_reassembled(dir);
}
-char Stream::missed_packets(Flow* flow, char dir)
+bool Stream::missed_packets(Flow* flow, uint8_t dir)
{
- if (!flow || flow->protocol != PktType::TCP)
- return 1;
-
- return StreamPacketsMissingTcp(flow, dir);
+ assert(flow && flow->session);
+ return flow->session->are_packets_missing(dir);
}
* TCP only.
*/
int ignore_session(
- const sfip_t* addr1, uint16_t p1, const sfip_t* addr2, uint16_t p2,
- uint8_t proto, char dir, uint32_t ppId);
+ const sfip_t *addr1, uint16_t p1, const sfip_t *addr2, uint16_t p2,
+ PktType, char dir, uint32_t ppId);
/* Resume inspection for session.
*/
* Returns
* true/false
*/
- static char is_stream_sequenced(Flow*, char dir);
+ static bool is_stream_sequenced(Flow*, uint8_t dir);
/* Get whether there are missing packets before, after or
* before and after reassembled buffer
* SSN_MISSING_AFTER if missing after
* SSN_MISSING_NONE if none missing
*/
- static int missing_in_reassembled(Flow*, char dir);
+ static int missing_in_reassembled(Flow*, uint8_t dir);
/* Get true/false as to whether packets were missed on
* the stream
* Returns
* true/false
*/
- static char missed_packets(Flow*, char dir);
+ static bool missed_packets(Flow*, uint8_t dir);
/* Get the protocol identifier from a stream
*
// initialize response count and expiration time
static void init_active_response(Packet*, Flow*);
- static bool is_paf_active(Flow*, bool toServer);
static void set_splitter(Flow*, bool toServer, class StreamSplitter* = nullptr);
static StreamSplitter* get_splitter(Flow*, bool toServer);
+ static bool is_paf_active(Flow*, bool toServer);
/* Turn off inspection for potential session.
* Adds session identifiers to a hash table.
* -1 on failure
*/
int set_application_protocol_id_expected(
- const sfip_t* a1, uint16_t p1, const sfip_t* a2, uint16_t p2, uint8_t proto,
+ const sfip_t *a1, uint16_t p1, const sfip_t *a2, uint16_t p2, PktType,
int16_t appId, FlowData*);
/** Retrieve application session data based on the lookup tuples for
* Application Data reference (pointer)
*/
static FlowData* get_application_data_from_ip_port(
- const sfip_t* a1, uint16_t p1, const sfip_t* a2, uint16_t p2, uint8_t proto,
+ uint8_t type, uint8_t proto,
+ const sfip_t *a1, uint16_t p1, const sfip_t *a2, uint16_t p2,
uint16_t vlanId, uint32_t mplsId, uint16_t addrSpaceId, unsigned flow_id);
/* Get the application data from the session key
* Stream session pointer
*/
static Flow* get_session_ptr_from_ip_port(
- const sfip_t* a1, uint16_t p1, const sfip_t* a2, uint16_t p2, uint8_t proto,
+ uint8_t type, uint8_t proto,
+ const sfip_t *a1, uint16_t p1, const sfip_t *a2, uint16_t p2,
uint16_t vlanId, uint32_t mplsId, uint16_t addrSpaceId);
/* Delete the session if it is in the closed session state.
extern const BaseApi* nin_stream_icmp;
extern const BaseApi* nin_stream_tcp;
extern const BaseApi* nin_stream_udp;
+extern const BaseApi* nin_stream_user;
+extern const BaseApi* nin_stream_file;
+
+extern const BaseApi* ips_stream_reassemble;
+extern const BaseApi* ips_stream_size;
const BaseApi* stream_inspectors[] =
{
nin_stream_icmp,
nin_stream_tcp,
nin_stream_udp,
+ nin_stream_user,
+ nin_stream_file,
+
+ ips_stream_reassemble,
+ ips_stream_size,
+
nullptr
};
add_library( stream_tcp STATIC
- stream_paf.cc
- stream_paf.h
stream_tcp.cc
stream_tcp.h
tcp_module.cc
noinst_LIBRARIES = libstream_tcp.a
libstream_tcp_a_SOURCES = \
-stream_paf.cc \
-stream_paf.h \
stream_tcp.cc \
stream_tcp.h \
tcp_module.cc \
void tcp_reset_stats();
void tcp_show(StreamTcpConfig*);
-// Stream support
-int StreamFlushListener(Packet*, Flow*);
-int StreamFlushTalker(Packet*, Flow*);
-int StreamFlushClient(Packet*, Flow*);
-int StreamFlushServer(Packet*, Flow*);
-void StreamTcpSessionClear(Flow*);
-char StreamGetReassemblyDirectionTcp(Flow*);
-
-int StreamAddSessionAlertTcp(Flow*, Packet*, uint32_t gid, uint32_t sid);
-int StreamCheckSessionAlertTcp(Flow*, Packet*, uint32_t gid, uint32_t sid);
-int StreamUpdateSessionAlertTcp(
- Flow*, Packet*, uint32_t gid, uint32_t sid, uint32_t event_id, uint32_t event_second);
-
-void StreamSetExtraDataTcp(Flow*, Packet*, uint32_t flag);
-void StreamClearExtraDataTcp(Flow*, Packet*, uint32_t flag);
-
-bool StreamGetReassemblyFlushPolicyTcp(Flow*, char dir);
-
-char StreamIsStreamSequencedTcp(Flow*, char dir);
-int StreamMissingInReassembledTcp(Flow*, char dir);
-char StreamPacketsMissingTcp(Flow*, char dir);
-
-void* get_paf_config(StreamTcpConfig*);
-void** StreamGetPAFUserDataTcp(Flow*, bool to_server);
-bool StreamIsPafActiveTcp(Flow*, bool to_server);
-
-void StreamSetSplitterTcp(Flow*, bool c2s, StreamSplitter*);
-StreamSplitter* StreamGetSplitterTcp(Flow*, bool c2s);
-
-int GetTcpRebuiltPackets(Packet*, Flow*, PacketIterator, void* userdata);
-int GetTcpStreamSegments(Packet*, Flow*, StreamSegmentIterator, void* userdata);
-
#endif
return new TcpSession(lwssn);
}
-static inline int SetupOK(const StreamTracker* st)
+static inline int SetupOK (const TcpTracker* st)
{
return ( (st->s_mgr.sub_state & SUB_SETUP_OK) == SUB_SETUP_OK );
}
-static inline uint32_t SegsToFlush(const StreamTracker* st, unsigned max)
+static inline uint32_t SegsToFlush (const TcpTracker* st, unsigned max)
{
uint32_t n = st->seg_count - st->flush_count;
- StreamSegment* s;
+ TcpSegment* s;
if ( !n || max == 1 )
return n;
return n;
}
-static inline bool DataToFlush(const StreamTracker* st)
+static inline bool DataToFlush (const TcpTracker* st)
{
// needed by stream_reassemble:action disable; can fire on rebuilt
// packets, yanking the splitter out from under us :(
static int ProcessTcp(Flow*, Packet*, TcpDataBlock*,
StreamTcpConfig*);
static inline int CheckFlushPolicyOnData(
- TcpSession*, StreamTracker*, StreamTracker*, Packet*);
+ TcpSession *, TcpTracker *, TcpTracker *, Packet *);
static inline int CheckFlushPolicyOnAck(
- TcpSession*, StreamTracker*, StreamTracker*, Packet*);
-static void StreamSeglistAddNode(StreamTracker*, StreamSegment*,
- StreamSegment*);
-static int StreamSeglistDeleteNode(StreamTracker*, StreamSegment*);
-static int StreamSeglistDeleteNodeTrim(StreamTracker*, StreamSegment*, uint32_t flush_seq);
+ TcpSession *, TcpTracker *, TcpTracker *, Packet *);
+static void StreamSeglistAddNode(TcpTracker *, TcpSegment *,
+ TcpSegment *);
+static int StreamSeglistDeleteNode(TcpTracker*, TcpSegment*);
+static int StreamSeglistDeleteNodeTrim(TcpTracker*, TcpSegment*, uint32_t flush_seq);
static int AddStreamNode(
- StreamTracker*, Packet*, TcpDataBlock*,
+ TcpTracker*, Packet*, TcpDataBlock*,
int16_t len, uint32_t slide, uint32_t trunc,
- uint32_t seq, StreamSegment* left, StreamSegment** retSeg);
+ uint32_t seq, TcpSegment *left, TcpSegment **retSeg);
static int DupStreamNode(
Packet*,
- StreamTracker*,
- StreamSegment* left,
- StreamSegment** retSeg);
+ TcpTracker*,
+ TcpSegment* left,
+ TcpSegment** retSeg);
static uint32_t StreamGetWscale(Packet*, uint16_t*);
static uint32_t StreamPacketHasWscale(Packet*);
static THREAD_LOCAL Packet* cleanup_pkt = nullptr;
/* F U N C T I O N S **********************************************/
-static inline void init_flush_policy(Flow*, StreamTracker* trk)
+static inline void init_flush_policy(Flow*, TcpTracker* trk)
{
if ( !trk->splitter )
trk->flush_policy = STREAM_FLPOLICY_IGNORE;
trk->flush_policy = STREAM_FLPOLICY_ON_DATA;
}
-bool StreamIsPafActiveTcp(Flow* lwssn, bool c2s)
-{
- TcpSession* tcpssn = (TcpSession*)lwssn->session;
- StreamSplitter* ss = c2s ? tcpssn->server.splitter : tcpssn->client.splitter;
-
- return ss && ss->is_paf();
-}
-
-void StreamSetSplitterTcp(Flow* lwssn, bool c2s, StreamSplitter* ss)
-{
- TcpSession* tcpssn = (TcpSession*)lwssn->session;
- StreamTracker* trk;
-
- if ( c2s )
- {
- trk = &tcpssn->server;
- }
- else
- {
- trk = &tcpssn->client;
- }
-
- if ( trk->splitter && tcpssn->tcp_init )
- delete trk->splitter;
-
- trk->splitter = ss;
-
- if ( ss )
- s5_paf_setup(&trk->paf_state);
-}
-
-StreamSplitter* StreamGetSplitterTcp(Flow* lwssn, bool c2s)
-{
- TcpSession* tcpssn = (TcpSession*)lwssn->session;
- StreamTracker* trk;
-
- if ( c2s )
- {
- trk = &tcpssn->server;
- }
- else
- {
- trk = &tcpssn->client;
- }
-
- return trk->splitter;
-}
-
-void StreamUpdatePerfBaseState(SFBASE* sf_base,
- Flow* lwssn,
- char newState)
+void StreamUpdatePerfBaseState(SFBASE *sf_base, Flow *lwssn, char newState)
{
if (!lwssn)
{
LogMessage(" stq_get_seq: %d\n", s->stq_get_seq);
}
-static void PrintStreamTracker(StreamTracker* s)
+static void PrintTcpTracker(TcpTracker *s)
{
- LogMessage(" + StreamTracker +\n");
+ LogMessage(" + TcpTracker +\n");
LogMessage(" isn: 0x%X\n", s->isn);
LogMessage(" ts_last: %u\n", s->ts_last);
LogMessage(" wscale: %u\n", s->wscale);
LogMessage(" flags: 0x%X\n", ts->flow->ssn_state.session_flags);
LogMessage("Client Tracker:\n");
- PrintStreamTracker(&ts->client);
+ PrintTcpTracker(&ts->client);
LogMessage("Server Tracker:\n");
- PrintStreamTracker(&ts->server);
+ PrintTcpTracker(&ts->server);
}
static void PrintTcpDataBlock(TcpDataBlock* tdb)
return (SEQ_GEQ(cur, low) && SEQ_LEQ(cur, high));
}
-#define SSNFLAG_SEEN_BOTH (SSNFLAG_SEEN_SERVER | SSNFLAG_SEEN_CLIENT)
-static inline bool TwoWayTraffic(Flow* lwssn)
-{
- return ( (lwssn->ssn_state.session_flags & SSNFLAG_SEEN_BOTH) == SSNFLAG_SEEN_BOTH );
-}
-
static inline uint32_t StreamGetWindow(
- Flow* lwssn, StreamTracker* st, TcpDataBlock* tdb)
+ Flow* lwssn, TcpTracker* st, TcpDataBlock* tdb)
{
int32_t window;
}
// one way zero window is unitialized
// two way zero window is actually closed (regardless of scaling)
- else if ( TwoWayTraffic(lwssn) )
+ else if ( lwssn->two_way_traffic() )
return st->l_window;
// ensure the data is in the window
}
// ack number must ack syn
-static inline int ValidRstSynSent(StreamTracker* st, TcpDataBlock* tdb)
+static inline int ValidRstSynSent(TcpTracker *st, TcpDataBlock *tdb)
{
return tdb->ack == st->l_unackd;
}
// validate here based on how various implementations actually
// handle a rst.
static inline int ValidRst(
- Flow* lwssn, StreamTracker* st, TcpDataBlock* tdb)
+ Flow* lwssn, TcpTracker *st, TcpDataBlock *tdb)
{
STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
"Checking end_seq (%X) > r_win_base (%X) && "
}
static inline int ValidTimestamp(
- StreamTracker* talker, StreamTracker* listener, TcpDataBlock* tdb,
- Packet* p, int* eventcode, int* got_ts)
+ TcpTracker *talker, TcpTracker *listener, TcpDataBlock *tdb,
+ Packet *p, int *eventcode, int *got_ts)
{
if ( p->ptrs.tcph->th_flags & TH_RST or
listener->config->policy == STREAM_POLICY_PROXY )
// or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND
//
static inline int ValidSeq(
- const Packet* p, Flow* lwssn, StreamTracker* st, TcpDataBlock* tdb)
+ const Packet* p, Flow* lwssn, TcpTracker *st, TcpDataBlock *tdb)
{
uint32_t win = StreamGetWindow(lwssn, st, tdb);
#else
static inline int ValidSeq(
- const Packet* p, Flow* lwssn, StreamTracker* st, TcpDataBlock* tdb)
+ const Packet* p, Flow* lwssn, TcpTracker *st, TcpDataBlock *tdb)
{
int right_ok;
uint32_t left_seq;
#endif
static inline void UpdateSsn(
- Packet*, StreamTracker* rcv, StreamTracker* snd, TcpDataBlock* tdb)
+ Packet*, TcpTracker *rcv, TcpTracker *snd, TcpDataBlock *tdb)
{
#if 0
if (
{
// walk the seglist until a gap or tdb->ack whichever is first
// if a gap exists prior to ack, move ack back to start of gap
- StreamSegment* seg = snd->seglist;
+ TcpSegment* seg = snd->seglist;
// FIXIT-L must check ack oob with empty seglist
// FIXIT-L add lower gap bound to tracker for efficiency?
#endif
}
-static void SegmentFree(StreamSegment* seg)
+static void SegmentFree (TcpSegment *seg)
{
- unsigned dropped = sizeof(StreamSegment);
+ unsigned dropped = sizeof(TcpSegment);
STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
"Dumping segment at seq %X, size %d, caplen %d\n",
"SegmentFree dropped %d bytes\n", dropped); );
}
-static void DeleteSeglist(StreamSegment* listhead)
+static void DeleteSeglist(TcpSegment *listhead)
{
- StreamSegment* idx = listhead;
- StreamSegment* dump_me;
+ TcpSegment *idx = listhead;
+ TcpSegment *dump_me;
int i = 0;
STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
}
static inline int purge_alerts(
- StreamTracker* st, uint32_t flush_seq, Flow* flow)
+ TcpTracker *st, uint32_t flush_seq, Flow* flow)
{
int i;
int new_count = 0;
return new_count;
}
-static inline int purge_to_seq(TcpSession* tcpssn, StreamTracker* st, uint32_t flush_seq)
+static inline int purge_to_seq(TcpSession *tcpssn, TcpTracker *st, uint32_t flush_seq)
{
- StreamSegment* ss = NULL;
- StreamSegment* dump_me = NULL;
+ TcpSegment *ss = NULL;
+ TcpSegment *dump_me = NULL;
int purged_bytes = 0;
uint32_t last_ts = 0;
return purged_bytes;
}
-static inline void purge_all(StreamTracker* st)
+static inline void purge_all (TcpTracker *st)
{
DeleteSeglist(st->seglist);
st->seglist = st->seglist_tail = st->seglist_next = NULL;
// initial part of a segment
// * FIXIT-L need flag to mark any reassembled packets that have a gap
// (if we reassemble such)
-static inline int purge_flushed_ackd(TcpSession* tcpssn, StreamTracker* st)
+static inline int purge_flushed_ackd (TcpSession *tcpssn, TcpTracker *st)
{
- StreamSegment* seg = st->seglist;
+ TcpSegment* seg = st->seglist;
uint32_t seq;
if ( !st->seglist )
}
static inline unsigned int getSegmentFlushSize(
- StreamTracker* st,
- StreamSegment* ss,
+ TcpTracker* st,
+ TcpSegment *ss,
uint32_t to_seq,
- unsigned int flushBufSize
- )
+ unsigned int flushBufSize)
{
unsigned int flushSize = ss->size;
flushSize = flushBufSize;
// copy only to flush point
- if ( s5_paf_active(&st->paf_state) && SEQ_GT(ss->seq + flushSize, to_seq) )
+ if ( paf_active(&st->paf_state) && SEQ_GT(ss->seq + flushSize, to_seq) )
flushSize = to_seq - ss->seq;
return flushSize;
* flush the client seglist up to the most recently acked segment
*/
static int FlushStream(
- Packet* p, StreamTracker* st, uint32_t toSeq, uint8_t* flushbuf,
- const uint8_t* flushbuf_end)
+ Packet* p, TcpTracker *st, uint32_t toSeq, uint8_t *flushbuf,
+ const uint8_t *flushbuf_end)
{
uint16_t bytes_flushed = 0;
STREAM_DEBUG_WRAP(uint32_t bytes_queued = st->seg_bytes_logical; );
while ( SEQ_LT(st->seglist_next->seq, toSeq) )
{
- StreamSegment* ss = st->seglist_next, * sr;
+ TcpSegment* ss = st->seglist_next, * sr;
unsigned flushbuf_size = flushbuf_end - flushbuf;
unsigned bytes_to_copy = getSegmentFlushSize(st, ss, toSeq, flushbuf_size);
unsigned bytes_copied = 0;
}
static inline int _flush_to_seq(
- TcpSession* tcpssn, StreamTracker* st, uint32_t bytes, Packet* p, uint32_t dir)
+ TcpSession *tcpssn, TcpTracker *st, uint32_t bytes, Packet *p, uint32_t dir)
{
uint32_t stop_seq;
uint32_t footprint;
* and fire it thru the system.
*/
static inline int flush_to_seq(
- TcpSession* tcpssn, StreamTracker* st, uint32_t bytes, Packet* p, uint32_t dir)
+ TcpSession *tcpssn, TcpTracker *st, uint32_t bytes, Packet *p, uint32_t dir)
{
STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
"In flush_to_seq()\n"); );
* between our base sequence and the last ack'd sequence we
* received
*/
-static inline uint32_t get_q_footprint(StreamTracker* st)
+static inline uint32_t get_q_footprint(TcpTracker *st)
{
uint32_t fp;
// FIXIT-L get_q_sequenced() performance could possibly be
// boosted by tracking sequenced bytes as seglist is updated
// to avoid the while loop, etc. below.
-static inline uint32_t get_q_sequenced(StreamTracker* st)
+static inline uint32_t get_q_sequenced(TcpTracker *st)
{
uint32_t len;
- StreamSegment* seg = st ? st->seglist : NULL;
- StreamSegment* base = NULL;
+ TcpSegment* seg = st ? st->seglist : NULL;
+ TcpSegment* base = NULL;
if ( !seg )
return 0;
}
static inline int flush_ackd(
- TcpSession* tcpssn, StreamTracker* st, Packet* p, uint32_t dir)
+ TcpSession *tcpssn, TcpTracker *st, Packet *p, uint32_t dir)
{
uint32_t bytes = get_q_footprint(st);
return flush_to_seq(tcpssn, st, bytes, p, dir);
// CheckFlushPolicyOn*() with the exception that for the *OnAck() case,
// any available ackd data must be flushed in both directions.
static inline int flush_stream(
- TcpSession* tcpssn, StreamTracker* st, Packet* p, uint32_t dir)
+ TcpSession *tcpssn, TcpTracker *st, Packet *p, uint32_t dir)
{
// this is not always redundant; stream_reassemble rule option causes trouble
if ( !st->flush_policy )
return flush_ackd(tcpssn, st, p, dir);
}
-int StreamFlushServer(Packet* p, Flow* lwssn)
-{
- int flushed;
- TcpSession* tcpssn = (TcpSession*)lwssn->session;
- StreamTracker* flushTracker = &tcpssn->server;
-
- flushTracker->flags |= TF_FORCE_FLUSH;
-
- /* If this is a rebuilt packet, don't flush now because we'll
- * overwrite the packet being processed.
- */
- if (p->packet_flags & PKT_REBUILT_STREAM)
- {
- /* We'll check & clear the TF_FORCE_FLUSH next time through */
- return 0;
- }
-
- /* Need to convert the addresses to network order */
- flushed = flush_stream(tcpssn, flushTracker, p, PKT_FROM_SERVER);
-
- if (flushed)
- purge_flushed_ackd(tcpssn, flushTracker);
-
- flushTracker->flags &= ~TF_FORCE_FLUSH;
-
- return flushed;
-}
-
-int StreamFlushClient(Packet* p, Flow* lwssn)
-{
- int flushed;
- TcpSession* tcpssn = (TcpSession*)lwssn->session;
- StreamTracker* flushTracker = &tcpssn->client;
-
- flushTracker->flags |= TF_FORCE_FLUSH;
-
- /* If this is a rebuilt packet, don't flush now because we'll
- * overwrite the packet being processed.
- */
- if (p->packet_flags & PKT_REBUILT_STREAM)
- {
- /* We'll check & clear the TF_FORCE_FLUSH next time through */
- return 0;
- }
-
- /* Need to convert the addresses to network order */
- flushed = flush_stream(tcpssn, flushTracker, p, PKT_FROM_CLIENT);
-
- if (flushed)
- purge_flushed_ackd(tcpssn, flushTracker);
-
- flushTracker->flags &= ~TF_FORCE_FLUSH;
-
- return flushed;
-}
-
-int StreamFlushListener(Packet* p, Flow* lwssn)
-{
- StreamTracker* listener = NULL;
- int dir = 0;
- int flushed = 0;
-
- TcpSession* tcpssn = (TcpSession*)lwssn->session;
-
- /* figure out direction of this packet -- we should've already
- * looked at it, so the packet_flags are already set. */
- if (p->packet_flags & PKT_FROM_SERVER)
- {
- STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
- "Flushing listener on packet from server\n"); );
- listener = &tcpssn->client;
- /* dir of flush is the data from the opposite side */
- dir = PKT_FROM_SERVER;
- }
- else if (p->packet_flags & PKT_FROM_CLIENT)
- {
- STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
- "Flushing listener on packet from client\n"); );
- listener = &tcpssn->server;
- /* dir of flush is the data from the opposite side */
- dir = PKT_FROM_CLIENT;
- }
-
- if (dir != 0)
- {
- listener->flags |= TF_FORCE_FLUSH;
- flushed = flush_stream(tcpssn, listener, p, dir);
-
- if (flushed)
- purge_flushed_ackd(tcpssn, listener);
-
- listener->flags &= ~TF_FORCE_FLUSH;
- }
-
- return flushed;
-}
-
-int StreamFlushTalker(Packet* p, Flow* lwssn)
-{
- StreamTracker* talker = NULL;
- int dir = 0;
- int flushed = 0;
-
- TcpSession* tcpssn = (TcpSession*)lwssn->session;
-
- /* figure out direction of this packet -- we should've already
- * looked at it, so the packet_flags are already set. */
- if (p->packet_flags & PKT_FROM_SERVER)
- {
- STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
- "Flushing talker on packet from server\n"); );
- talker = &tcpssn->server;
- /* dir of flush is the data from the opposite side */
- dir = PKT_FROM_CLIENT;
- }
- else if (p->packet_flags & PKT_FROM_CLIENT)
- {
- STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
- "Flushing talker on packet from client\n"); );
- talker = &tcpssn->client;
- /* dir of flush is the data from the opposite side */
- dir = PKT_FROM_SERVER;
- }
-
- if (dir != 0)
- {
- talker->flags |= TF_FORCE_FLUSH;
- flushed = flush_stream(tcpssn, talker, p, dir);
-
- if (flushed)
- purge_flushed_ackd(tcpssn, talker);
-
- talker->flags &= ~TF_FORCE_FLUSH;
- }
-
- return flushed;
-}
-
-static void TcpSessionClear(Flow* lwssn, TcpSession* tcpssn, int freeApplicationData)
+static void TcpSessionClear (Flow* lwssn, TcpSession* tcpssn, int freeApplicationData)
{
STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
"In TcpSessionClear, %lu bytes in use\n", tcp_memcap->used()); );
purge_all(&tcpssn->client);
purge_all(&tcpssn->server);
- s5_paf_clear(&tcpssn->client.paf_state);
- s5_paf_clear(&tcpssn->server.paf_state);
+ paf_clear(&tcpssn->client.paf_state);
+ paf_clear(&tcpssn->server.paf_state);
// update light-weight state
if ( freeApplicationData == 2 )
STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
"After cleaning, %lu bytes in use\n", tcp_memcap->used()); );
- memset(&tcpssn->client, 0, sizeof(tcpssn->client));
- memset(&tcpssn->server, 0, sizeof(tcpssn->server));
-
tcpssn->lws_init = tcpssn->tcp_init = false;
}
static void final_flush(
- Flow* lwssn, TcpSession* tcpssn, StreamTracker& trk, Packet* p,
+ Flow* lwssn, TcpSession* tcpssn, TcpTracker& trk, Packet* p,
PegCount& peg, uint32_t flag)
{
if ( !p )
}
#ifdef SEG_TEST
-static void CheckSegments(const StreamTracker* a)
+static void CheckSegments (const TcpTracker* a)
{
- StreamSegment* ss = a->seglist;
+ TcpSegment* ss = a->seglist;
uint32_t sx = ss ? ss->seq : 0;
while ( ss )
"IGN", "FPR", "PRE", "PRO", "PAF"
};
-static void TraceSegments(const StreamTracker* a)
+static void TraceSegments (const TcpTracker* a)
{
- StreamSegment* ss = a->seglist;
+ TcpSegment* ss = a->seglist;
uint32_t sx = a->r_win_base;
unsigned segs = 0, bytes = 0;
}
static void TraceState(
- const StreamTracker* a, const StreamTracker* b, const char* s)
+ const TcpTracker* a, const TcpTracker* b, const char* s)
{
uint32_t why = a->l_nxt_seq ? LCL(a, l_nxt_seq) : 0;
)
{
const TcpSession* ssn = (TcpSession*)lws->session;
- const StreamTracker* srv = ssn ? &ssn->server : NULL;
- const StreamTracker* cli = ssn ? &ssn->client : NULL;
+ const TcpTracker* srv = ssn ? &ssn->server : NULL;
+ const TcpTracker* cli = ssn ? &ssn->client : NULL;
const char* cdir = "?", * sdir = "?";
uint32_t txd = 0, rxd = 0;
{
sdir = "SRV>";
cdir = "CLI<";
- if ( srv )
+
+ if ( ssn->tcp_init )
+ {
txd = srv->isn;
- if ( cli )
rxd = cli->isn;
+ }
}
else if ( p->packet_flags & PKT_FROM_CLIENT )
{
sdir = "SRV<";
cdir = "CLI>";
- if ( cli )
+
+ if ( ssn->tcp_init )
+ {
txd = cli->isn;
- if ( srv )
rxd = srv->isn;
+ }
}
TraceEvent(p, tdb, txd, rxd);
- if ( !cli->s_mgr.state && !srv->s_mgr.state )
+ if ( !ssn->tcp_init )
return;
- if ( lws )
+ if ( lws && ssn->lws_init )
TraceSession(lws);
if ( lws && !event )
{
- if ( cli )
- TraceState(cli, srv, cdir);
- if ( srv )
- TraceState(srv, cli, sdir);
+ TraceState(cli, srv, cdir);
+ TraceState(srv, cli, sdir);
}
}
}
#if 0
-static inline int IsWellFormed(Packet* p, StreamTracker* ts)
+static inline int IsWellFormed(Packet *p, TcpTracker *ts)
{
return ( !ts->mss || (p->dsize <= ts->mss) );
}
static void FinishServerInit(Packet* p, TcpDataBlock* tdb, TcpSession* ssn)
{
- StreamTracker* server;
- StreamTracker* client;
+ TcpTracker *server;
+ TcpTracker *client;
if (!ssn)
{
}
static void NewQueue(
- StreamTracker* st, Packet* p, TcpDataBlock* tdb)
+ TcpTracker *st, Packet *p, TcpDataBlock *tdb)
{
- StreamSegment* ss = NULL;
+ TcpSegment *ss = NULL;
uint32_t overlap = 0;
PROFILE_VARS;
MODULE_PROFILE_END(s5TcpInsertPerfStats);
}
-static inline int SegmentFastTrack(StreamSegment* tail, TcpDataBlock* tdb)
+static inline int SegmentFastTrack(TcpSegment *tail, TcpDataBlock *tdb)
{
STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
"Checking seq for fast track: %X > %X\n", tdb->seq,
return 0;
}
-static inline StreamSegment* SegmentAlloc(
+static inline TcpSegment* SegmentAlloc(
Packet* p, const struct timeval* tv, uint32_t caplen, uint32_t pktlen, const uint8_t* pkt)
{
- StreamSegment* ss;
+ TcpSegment* ss;
unsigned size = sizeof(*ss);
if ( caplen > 0 )
tcp_memcap->dealloc(size);
return NULL;
}
- flow_con->prune_flows(IPPROTO_TCP, p);
+ flow_con->prune_flows(PktType::TCP, p);
}
- ss = (StreamSegment*)SnortAlloc(size);
+ ss = (TcpSegment*)SnortAlloc(size);
ss->tv.tv_sec = tv->tv_sec;
ss->tv.tv_usec = tv->tv_usec;
}
static int AddStreamNode(
- StreamTracker* st, Packet* p,
+ TcpTracker *st, Packet *p,
TcpDataBlock* tdb,
int16_t len,
uint32_t slide,
uint32_t trunc,
uint32_t seq,
- StreamSegment* left,
- StreamSegment** retSeg)
+ TcpSegment *left,
+ TcpSegment **retSeg)
{
- StreamSegment* ss = NULL;
+ TcpSegment *ss = NULL;
int32_t newSize = len - slide - trunc;
if (newSize <= 0)
#ifdef DEBUG_STREAM_EX
{
- StreamSegment* idx = st->seglist;
+ TcpSegment *idx = st->seglist;
unsigned long i = 0;
STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
"Dumping seglist, %d segments\n", st->seg_count); );
return STREAM_INSERT_OK;
}
-static int DupStreamNode(Packet* p,
- StreamTracker* st,
- StreamSegment* left,
- StreamSegment** retSeg)
+static int DupStreamNode(
+ Packet *p, TcpTracker *st, TcpSegment *left, TcpSegment **retSeg)
{
- StreamSegment* ss = SegmentAlloc(p, &left->tv, left->caplen, left->pktlen, left->pkt);
+ TcpSegment* ss = SegmentAlloc(p, &left->tv, left->caplen, left->pktlen, left->pkt);
if ( !ss )
return STREAM_INSERT_FAILED;
return STREAM_INSERT_OK;
}
-static inline bool IsRetransmit(StreamSegment* seg, const uint8_t* rdata,
- uint16_t rsize, uint32_t rseq)
+static inline bool IsRetransmit(
+ TcpSegment *seg, const uint8_t *rdata, uint16_t rsize, uint32_t rseq)
{
// If seg->orig_size == seg->size, then it's sequence number wasn't adjusted
// so can just do a straight compare of the sequence numbers.
static inline void RetransmitProcess(Packet* p, TcpSession*)
{
// Data has already been analyzed so don't bother looking at it again.
- DisableDetect(p);
-
- DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Allowing retransmitted data "
- "-- not blocked previously\n"); );
+ DisableDetect( p );
}
static inline void RetransmitHandle(Packet* p, TcpSession* tcpssn)
{
- DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Calling SE_REXMIT Handler\n"); );
tcpssn->flow->call_handlers(p, false);
}
static inline void EndOfFileHandle(Packet* p, TcpSession* tcpssn)
{
- DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Calling SE_EOF Handler\n"); );
tcpssn->flow->call_handlers(p, true);
}
-static inline NormMode get_norm_ips(StreamTracker* st)
+static inline NormMode get_norm_ips(TcpTracker* st)
{
if ( st->config->policy == STREAM_POLICY_PROXY )
return NORM_MODE_OFF;
return Normalize_GetMode(NORM_TCP_IPS);
}
-static int StreamQueue(StreamTracker* st, Packet* p, TcpDataBlock* tdb,
- TcpSession* tcpssn)
+static int StreamQueue(TcpTracker *st, Packet *p, TcpDataBlock *tdb,
+ TcpSession *tcpssn)
{
- StreamSegment* ss = NULL;
- StreamSegment* left = NULL;
- StreamSegment* right = NULL;
- StreamSegment* dump_me = NULL;
+ TcpSegment *ss = NULL;
+ TcpSegment *left = NULL;
+ TcpSegment *right = NULL;
+ TcpSegment *dump_me = NULL;
uint32_t seq = tdb->seq;
uint32_t seq_end = tdb->end_seq;
uint16_t len = p->dsize;
uint32_t rseq = tdb->seq;
PROFILE_VARS;
STREAM_DEBUG_WRAP(
- StreamSegment *lastptr = NULL;
+ TcpSegment *lastptr = NULL;
uint32_t base_seq = st->seglist_base_seq;
int last = 0;
);
return ret;
}
-static void ProcessTcpStream(StreamTracker* rcv, TcpSession* tcpssn,
- Packet* p, TcpDataBlock* tdb,
+static void ProcessTcpStream(
+ TcpTracker *rcv, TcpSession *tcpssn,
+ Packet *p, TcpDataBlock *tdb,
StreamTcpConfig* config)
{
STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
#endif
if ((config->flags & STREAM_CONFIG_NO_ASYNC_REASSEMBLY) &&
- !TwoWayTraffic(tcpssn->flow))
+ !tcpssn->flow->two_way_traffic())
{
return;
}
}
static int ProcessTcpData(
- Packet* p, StreamTracker* listener, TcpSession* tcpssn,
- TcpDataBlock* tdb, StreamTcpConfig* config)
+ Packet *p, TcpTracker *listener, TcpSession *tcpssn,
+ TcpDataBlock *tdb, StreamTcpConfig *config)
{
PROFILE_VARS;
MODULE_PROFILE_START(s5TcpDataPerfStats);
return STREAM_UNALIGNED;
}
-void SetTcpReassemblyPolicy(StreamTracker* st)
+void SetTcpReassemblyPolicy(TcpTracker *st)
{
st->reassembly_policy = GetTcpReassemblyPolicy(st->os_policy);
}
* there is no guarantee of memory alignment (and thus performance
* issues similar to memcmp). */
static inline int ValidMacAddress(
- StreamTracker* talker, StreamTracker* listener, Packet* p)
+ TcpTracker *talker, TcpTracker *listener, Packet *p)
{
int i, j, ret = 0;
if ( (lwssn->ssn_state.session_flags & SSNFLAG_CLIENT_SWAP) &&
!(lwssn->ssn_state.session_flags & SSNFLAG_CLIENT_SWAPPED) )
{
- StreamTracker trk = tmp->client;
+ TcpTracker trk = tmp->client;
sfip_t ip = lwssn->client_ip;
uint16_t port = lwssn->client_port;
lwssn->client_port = lwssn->server_port;
lwssn->server_port = port;
- if ( !TwoWayTraffic(lwssn) )
+ if ( !lwssn->two_way_traffic() )
{
if ( lwssn->ssn_state.session_flags & SSNFLAG_SEEN_CLIENT )
{
}
static int RepeatedSyn(
- StreamTracker* listener, StreamTracker* talker,
- TcpDataBlock* tdb, TcpSession* tcpssn)
+ TcpTracker *listener, TcpTracker *talker,
+ TcpDataBlock *tdb, TcpSession *tcpssn)
{
switch (listener->os_policy)
{
int got_ts = 0;
int new_ssn = 0;
int ts_action = ACTION_NOTHING;
- TcpSession* tcpssn = NULL;
- StreamTracker* talker = NULL;
- StreamTracker* listener = NULL;
- STREAM_DEBUG_WRAP(char* t = NULL; char* l = NULL; )
+ TcpSession *tcpssn = NULL;
+ TcpTracker *talker = NULL;
+ TcpTracker *listener = NULL;
+ STREAM_DEBUG_WRAP(char *t = NULL; char *l = NULL;)
PROFILE_VARS;
if (lwssn->protocol != PktType::TCP)
{
if ( talker && (talker->flags & TF_FORCE_FLUSH) )
{
- StreamFlushTalker(p, lwssn);
+ tcpssn->flush_talker(p);
talker->flags &= ~TF_FORCE_FLUSH;
}
if ( listener && (listener->flags & TF_FORCE_FLUSH) )
{
- StreamFlushListener(p, lwssn);
+ tcpssn->flush_listener(p);
listener->flags &= ~TF_FORCE_FLUSH;
}
p->packet_flags |= PKT_IGNORE;
listener->s_mgr.state == TCP_STATE_FIN_WAIT_2 ||
listener->s_mgr.state == TCP_STATE_CLOSE_WAIT ||
listener->s_mgr.state == TCP_STATE_CLOSING
- )
- {
- StreamFlushTalker(p, lwssn);
- StreamFlushListener(p, lwssn);
+ ) {
+ tcpssn->flush_talker(p);
+ tcpssn->flush_listener(p);
lwssn->free_application_data();
}
lwssn->ssn_state.session_flags |= SSNFLAG_RESET;
// sender of syn w/mss limits payloads from peer
// since we store mss on sender side, use listener mss
// same reasoning for window size
- StreamTracker* st = listener;
+ TcpTracker* st = listener;
// trim to fit in window and mss as needed
NormalTrimPayloadIfWin(
// see flush_pdu_ackd() for details
// the key difference is that we operate on forward moving data
// because we don't wait until it is acknowledged
-static inline int32_t flush_pdu_ips(
- TcpSession* ssn, StreamTracker* trk, uint32_t* flags)
+static inline uint32_t flush_pdu_ips(
+ TcpSession* ssn, TcpTracker* trk, uint32_t* flags)
{
- int32_t total = 0, avail;
- StreamSegment* seg;
+ uint32_t total = 0, avail;
+ TcpSegment* seg;
PROFILE_VARS;
MODULE_PROFILE_START(s5TcpPAFPerfStats);
avail = get_q_sequenced(trk);
seg = trk->seglist_next;
- // * must stop if gap (checked in s5_paf_check)
+ // * must stop if gap (checked in paf_check)
while ( seg && *flags && (total < avail) )
{
int32_t flush_pt;
uint32_t size = seg->size;
uint32_t end = seg->seq + seg->size;
- uint32_t pos = s5_paf_position(&trk->paf_state);
+ uint32_t pos = paf_position(&trk->paf_state);
total += size;
- if ( s5_paf_initialized(&trk->paf_state) && SEQ_LEQ(end, pos) )
+ if ( paf_initialized(&trk->paf_state) && SEQ_LEQ(end, pos) )
{
seg = seg->next;
continue;
}
- flush_pt = s5_paf_check(
+ flush_pt = paf_check(
trk->splitter, &trk->paf_state, ssn->flow,
seg->payload, size, total, seg->seq, flags);
MODULE_PROFILE_END(s5TcpPAFPerfStats);
// see flush_pdu_ackd()
- if ( !trk->splitter->is_paf() && avail > flush_pt )
+ if ( !trk->splitter->is_paf() && avail > (unsigned)flush_pt )
{
- s5_paf_jump(&trk->paf_state, avail - flush_pt);
+ paf_jump(&trk->paf_state, avail - (unsigned)flush_pt);
return avail;
}
return flush_pt;
return -1;
}
-static inline void fallback(StreamTracker* a)
+static inline void fallback(TcpTracker* a)
{
bool c2s = a->splitter->to_server();
}
static inline int CheckFlushPolicyOnData(
- TcpSession* tcpssn, StreamTracker* talker,
- StreamTracker* listener, Packet* p)
+ TcpSession *tcpssn, TcpTracker *talker,
+ TcpTracker *listener, Packet *p)
{
uint32_t flushed = 0;
// - if we partially scan a segment we must save state so we
// know where we left off and can resume scanning the remainder
-static inline int32_t flush_pdu_ackd(
- TcpSession* ssn, StreamTracker* trk, uint32_t* flags)
+static inline uint32_t flush_pdu_ackd(
+ TcpSession* ssn, TcpTracker* trk, uint32_t* flags)
{
uint32_t total = 0;
- StreamSegment* seg;
+ TcpSegment* seg;
PROFILE_VARS;
MODULE_PROFILE_START(s5TcpPAFPerfStats);
// * must stop if not acked
// * must use adjusted size of seg if not fully acked
- // * must stop if gap (checked in s5_paf_check)
+ // * must stop if gap (checked in paf_check)
while ( seg && *flags && SEQ_LT(seg->seq, trk->r_win_base) )
{
int32_t flush_pt;
uint32_t size = seg->size;
uint32_t end = seg->seq + seg->size;
- uint32_t pos = s5_paf_position(&trk->paf_state);
+ uint32_t pos = paf_position(&trk->paf_state);
- if ( s5_paf_initialized(&trk->paf_state) && SEQ_LEQ(end, pos) )
+ if ( paf_initialized(&trk->paf_state) && SEQ_LEQ(end, pos) )
{
total += size;
seg = seg->next;
total += size;
- flush_pt = s5_paf_check(
+ flush_pt = paf_check(
trk->splitter, &trk->paf_state, ssn->flow,
seg->payload, size, total, seg->seq, flags);
int32_t avail = (trk->r_win_base - trk->seglist_base_seq);
if ( avail > flush_pt )
{
- s5_paf_jump(&trk->paf_state, avail - flush_pt);
+ paf_jump(&trk->paf_state, avail - flush_pt);
return avail;
}
}
}
int CheckFlushPolicyOnAck(
- TcpSession* tcpssn, StreamTracker* talker,
- StreamTracker* listener, Packet* p)
+ TcpSession *tcpssn, TcpTracker *talker,
+ TcpTracker *listener, Packet *p)
{
uint32_t flushed = 0;
return flushed;
}
-static void StreamSeglistAddNode(StreamTracker* st, StreamSegment* prev,
- StreamSegment* ss)
+static void StreamSeglistAddNode(
+ TcpTracker *st, TcpSegment *prev, TcpSegment *ss)
{
tcpStats.segs_queued++;
st->seg_count++;
}
-static int StreamSeglistDeleteNode(StreamTracker* st, StreamSegment* seg)
+static int StreamSeglistDeleteNode (TcpTracker* st, TcpSegment* seg)
{
int ret;
assert(st && seg);
}
static int StreamSeglistDeleteNodeTrim(
- StreamTracker* st, StreamSegment* seg, uint32_t flush_seq)
+ TcpTracker* st, TcpSegment* seg, uint32_t flush_seq)
{
assert(st && seg);
- if ( s5_paf_active(&st->paf_state) &&
+ if ( paf_active(&st->paf_state) &&
((seg->seq + seg->size) > flush_seq) )
{
uint32_t delta = flush_seq - seg->seq;
return StreamSeglistDeleteNode(st, seg);
}
-/* Iterates through the packets that were reassembled for
- * logging of tagged packets.
- */
-int GetTcpRebuiltPackets(Packet* p, Flow* ssn,
- PacketIterator callback, void* userdata)
+bool StreamGetReassemblyFlushPolicyTcp(Flow *lwssn, char dir)
{
- int packets = 0;
- TcpSession* tcpssn = (TcpSession*)ssn->session;
- StreamTracker* st;
- StreamSegment* ss;
- uint32_t start_seq = ntohl(p->ptrs.tcph->th_seq);
- uint32_t end_seq = start_seq + p->dsize;
+ TcpSession *tcpssn = NULL;
- /* StreamTracker is the opposite of the ip of the reassembled
- * packet --> it came out the queue for the other side */
- if (sfip_equals(p->ptrs.ip_api.get_src(), &tcpssn->flow->client_ip))
+ if (!lwssn)
+ return false;
+
+ tcpssn = (TcpSession*)lwssn->session;
+
+ if (dir & SSN_DIR_FROM_CLIENT)
{
- st = &tcpssn->server;
+ return (char)tcpssn->client.flush_policy != STREAM_FLPOLICY_IGNORE;
}
- else
+
+ if (dir & SSN_DIR_FROM_SERVER)
{
- st = &tcpssn->client;
+ return (char)tcpssn->server.flush_policy != STREAM_FLPOLICY_IGNORE;
}
+ return false;
+}
- // skip over segments not covered by this reassembled packet
- for (ss = st->seglist; ss && SEQ_LT(ss->seq, start_seq); ss = ss->next)
- ;
-
- // return flushed segments only
- for (; ss && ss->buffered == SL_BUF_FLUSHED; ss = ss->next)
- {
- if (SEQ_GEQ(ss->seq,start_seq) && SEQ_LT(ss->seq, end_seq))
- {
- DAQ_PktHdr_t pkth;
- pkth.ts.tv_sec = ss->tv.tv_sec;
- pkth.ts.tv_usec = ss->tv.tv_usec;
- pkth.caplen = ss->caplen;
- pkth.pktlen = ss->pktlen;
+//-------------------------------------------------------------------------
+// TcpSession methods
+//-------------------------------------------------------------------------
- callback(&pkth, ss->pkt, userdata);
- packets++;
- }
- else
- break;
- }
+TcpSession::TcpSession(Flow* flow) : Session(flow)
+{
+ lws_init = tcp_init = false;
+}
- return packets;
+TcpSession::~TcpSession()
+{
+ if ( tcp_init )
+ TcpSessionClear(flow, (TcpSession*)flow->session, 1);
}
-/* Iterates through the packets that were reassembled for
- * logging of tagged packets.
- */
-int GetTcpStreamSegments(Packet* p, Flow* ssn,
- StreamSegmentIterator callback, void* userdata)
+void TcpSession::reset()
{
- int packets = 0;
- TcpSession* tcpssn = (TcpSession*)ssn->session;
- StreamTracker* st;
- StreamSegment* ss;
- uint32_t start_seq = ntohl(p->ptrs.tcph->th_seq);
- uint32_t end_seq = start_seq + p->dsize;
+ if ( tcp_init )
+ TcpSessionClear(flow, (TcpSession*)flow->session, 2);
+}
- /* StreamTracker is the opposite of the ip of the reassembled
- * packet --> it came out the queue for the other side */
- if (sfip_equals(p->ptrs.ip_api.get_src(), &tcpssn->flow->client_ip))
- st = &tcpssn->server;
- else
- st = &tcpssn->client;
+bool TcpSession::setup (Packet*)
+{
+ // FIXIT-L this it should not be necessary to reset here
+ reset();
- // skip over segments not covered by this reassembled packet
- for (ss = st->seglist; ss && SEQ_LT(ss->seq, start_seq); ss = ss->next)
- ;
+ lws_init = tcp_init = false;
+ event_mask = 0;
+ ecn = 0;
- // return flushed segments only
- for (; ss && ss->buffered == SL_BUF_FLUSHED; ss = ss->next)
- {
- if (SEQ_GEQ(ss->seq,start_seq) && SEQ_LT(ss->seq, end_seq))
- {
- DAQ_PktHdr_t pkth;
- pkth.ts.tv_sec = ss->tv.tv_sec;
- pkth.ts.tv_usec = ss->tv.tv_usec;
- pkth.caplen = ss->caplen;
- pkth.pktlen = ss->pktlen;
+ memset(&client, 0, offsetof(TcpTracker, alerts));
+ memset(&server, 0, offsetof(TcpTracker, alerts));
- if (callback(&pkth, ss->pkt, ss->data, ss->seq, userdata) != 0)
- return -1;
+#ifdef HAVE_DAQ_ADDRESS_SPACE_ID
+ ingress_index = egress_index = 0;
+ ingress_group = egress_group = 0;
+ daq_flags = address_space_id = 0;
+#endif
- packets++;
- }
- else
- break;
- }
+ tcpStats.sessions++;
+ return true;
+}
- return packets;
+void TcpSession::cleanup()
+{
+ // this flushes data and then calls TcpSessionClear()
+ TcpSessionCleanup(flow, 1);
}
-int StreamAddSessionAlertTcp(
- Flow* lwssn, Packet* p,
- uint32_t gid, uint32_t sid)
+// FIXIT-L this was originally called by Stream::drop_packet()
+// which is now calling Session::clear()
+void TcpSession::clear()
{
- StreamTracker* st;
- StreamAlertInfo* ai;
- TcpSession* tcpssn = (TcpSession*)lwssn->session;
+ if ( tcp_init )
+ // this does NOT flush data
+ TcpSessionClear(flow, this, 1);
+}
+
+void TcpSession::restart(Packet* p)
+{
+ TcpTracker* talker, * listener;
- if (sfip_equals(p->ptrs.ip_api.get_src(),&tcpssn->flow->client_ip))
+ if ( p->packet_flags & PKT_FROM_SERVER )
{
- st = &tcpssn->server;
+ talker = &server;
+ listener = &client;
}
else
{
- st = &tcpssn->client;
+ talker = &client;
+ listener = &server;
}
- if (st->alert_count >= MAX_SESSION_ALERTS)
- return 0;
+ // FIXIT-H on data / on ack must be based on flush policy
+ if ( p->dsize > 0 )
+ CheckFlushPolicyOnData(this, talker, listener, p);
- ai = st->alerts + st->alert_count;
- ai->gid = gid;
- ai->sid = sid;
- ai->seq = GET_PKT_SEQ(p);
+ if ( p->ptrs.tcph->is_ack() )
+ CheckFlushPolicyOnAck(this, talker, listener, p);
+}
- if ( p->ptrs.tcph->th_flags & TH_FIN )
- ai->seq--;
+void TcpSession::set_splitter(bool c2s, StreamSplitter* ss)
+{
+ TcpTracker* trk;
- st->alert_count++;
+ if ( c2s )
+ trk = &server;
+ else
+ trk = &client;
- return 1;
+ if ( trk->splitter && tcp_init )
+ delete trk->splitter;
+
+ trk->splitter = ss;
+
+ if ( ss )
+ paf_setup(&trk->paf_state);
}
-int StreamCheckSessionAlertTcp(Flow* lwssn, Packet* p, uint32_t gid, uint32_t sid)
+StreamSplitter* TcpSession::get_splitter(bool c2s)
{
- StreamTracker* st;
- int i;
- int iRet = 0;
- TcpSession* tcpssn = (TcpSession*)lwssn->session;
+ if ( c2s )
+ return server.splitter;
- /* If this is not a rebuilt packet, no need to check further */
- if (!(p->packet_flags & PKT_REBUILT_STREAM))
+ return client.splitter;
+}
+
+void TcpSession::flush_server(Packet *p)
+{
+ int flushed;
+ TcpTracker *flushTracker = &server;
+
+ flushTracker->flags |= TF_FORCE_FLUSH;
+
+ /* If this is a rebuilt packet, don't flush now because we'll
+ * overwrite the packet being processed.
+ */
+ if (p->packet_flags & PKT_REBUILT_STREAM)
{
- return 0;
+ /* We'll check & clear the TF_FORCE_FLUSH next time through */
+ return;
+ }
+
+ /* Need to convert the addresses to network order */
+ flushed = flush_stream(this, flushTracker, p, PKT_FROM_SERVER);
+
+ if (flushed)
+ purge_flushed_ackd(this, flushTracker);
+
+ flushTracker->flags &= ~TF_FORCE_FLUSH;
+}
+
+void TcpSession::flush_client(Packet* p)
+{
+ int flushed;
+ TcpTracker *flushTracker = &client;
+
+ flushTracker->flags |= TF_FORCE_FLUSH;
+
+ /* If this is a rebuilt packet, don't flush now because we'll
+ * overwrite the packet being processed.
+ */
+ if (p->packet_flags & PKT_REBUILT_STREAM)
+ {
+ /* We'll check & clear the TF_FORCE_FLUSH next time through */
+ return;
+ }
+
+ /* Need to convert the addresses to network order */
+ flushed = flush_stream(this, flushTracker, p, PKT_FROM_CLIENT);
+
+ if (flushed)
+ purge_flushed_ackd(this, flushTracker);
+
+ flushTracker->flags &= ~TF_FORCE_FLUSH;
+}
+
+void TcpSession::flush_listener(Packet* p)
+{
+ TcpTracker *listener = NULL;
+ int dir = 0;
+ int flushed = 0;
+
+ /* figure out direction of this packet -- we should've already
+ * looked at it, so the packet_flags are already set. */
+ if(p->packet_flags & PKT_FROM_SERVER)
+ {
+ STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
+ "Flushing listener on packet from server\n"););
+ listener = &client;
+ /* dir of flush is the data from the opposite side */
+ dir = PKT_FROM_SERVER;
+ }
+ else if (p->packet_flags & PKT_FROM_CLIENT)
+ {
+ STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
+ "Flushing listener on packet from client\n"););
+ listener = &server;
+ /* dir of flush is the data from the opposite side */
+ dir = PKT_FROM_CLIENT;
+ }
+
+ if (dir != 0)
+ {
+ listener->flags |= TF_FORCE_FLUSH;
+ flushed = flush_stream(this, listener, p, dir);
+
+ if (flushed)
+ purge_flushed_ackd(this, listener);
+
+ listener->flags &= ~TF_FORCE_FLUSH;
+ }
+}
+
+void TcpSession::flush_talker(Packet* p)
+{
+ TcpTracker *talker = NULL;
+ int dir = 0;
+ int flushed = 0;
+
+ /* figure out direction of this packet -- we should've already
+ * looked at it, so the packet_flags are already set. */
+ if(p->packet_flags & PKT_FROM_SERVER)
+ {
+ STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
+ "Flushing talker on packet from server\n"););
+ talker = &server;
+ /* dir of flush is the data from the opposite side */
+ dir = PKT_FROM_CLIENT;
+ }
+ else if (p->packet_flags & PKT_FROM_CLIENT)
+ {
+ STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
+ "Flushing talker on packet from client\n"););
+ talker = &client;
+ /* dir of flush is the data from the opposite side */
+ dir = PKT_FROM_SERVER;
}
- if (sfip_equals(p->ptrs.ip_api.get_src(), &tcpssn->flow->client_ip))
+ if (dir != 0)
{
- st = &tcpssn->server;
+ talker->flags |= TF_FORCE_FLUSH;
+ flushed = flush_stream(this, talker, p, dir);
+
+ if (flushed)
+ purge_flushed_ackd(this, talker);
+
+ talker->flags &= ~TF_FORCE_FLUSH;
}
+}
+
+/* Iterates through the packets that were reassembled for
+ * logging of tagged packets.
+ */
+int TcpSession::get_rebuilt_packets(
+ Packet* p, PacketIterator callback, void *userdata)
+{
+ int packets = 0;
+ TcpTracker *st;
+ TcpSegment *ss;
+ uint32_t start_seq = ntohl(p->ptrs.tcph->th_seq);
+ uint32_t end_seq = start_seq + p->dsize;
+
+ /* TcpTracker is the opposite of the ip of the reassembled
+ * packet --> it came out the queue for the other side */
+ if (sfip_equals(p->ptrs.ip_api.get_src(), &flow->client_ip))
+ st = &server;
else
+ st = &client;
+
+ // skip over segments not covered by this reassembled packet
+ for (ss = st->seglist; ss && SEQ_LT(ss->seq, start_seq); ss = ss->next);
+
+ // return flushed segments only
+ for (; ss && ss->buffered == SL_BUF_FLUSHED; ss = ss->next)
{
- st = &tcpssn->client;
+ if (SEQ_GEQ(ss->seq,start_seq) && SEQ_LT(ss->seq, end_seq))
+ {
+ DAQ_PktHdr_t pkth;
+ pkth.ts.tv_sec = ss->tv.tv_sec;
+ pkth.ts.tv_usec = ss->tv.tv_usec;
+ pkth.caplen = ss->caplen;
+ pkth.pktlen = ss->pktlen;
+
+ callback(&pkth, ss->pkt, userdata);
+ packets++;
+ }
+ else
+ break;
}
- for (i=0; i<st->alert_count; i++)
+ return packets;
+}
+
+/* Iterates through the packets that were reassembled for
+ * logging of tagged packets.
+ */
+int TcpSession::get_segments(
+ Packet* p, StreamSegmentIterator callback, void *userdata)
+{
+ int packets = 0;
+ TcpTracker *st;
+ TcpSegment *ss;
+ uint32_t start_seq = ntohl(p->ptrs.tcph->th_seq);
+ uint32_t end_seq = start_seq + p->dsize;
+
+ /* TcpTracker is the opposite of the ip of the reassembled
+ * packet --> it came out the queue for the other side */
+ if (sfip_equals(p->ptrs.ip_api.get_src(), &flow->client_ip))
+ st = &server;
+ else
+ st = &client;
+
+ // skip over segments not covered by this reassembled packet
+ for (ss = st->seglist; ss && SEQ_LT(ss->seq, start_seq); ss = ss->next);
+
+ // return flushed segments only
+ for (; ss && ss->buffered == SL_BUF_FLUSHED; ss = ss->next)
{
- /* This is a rebuilt packet and if we've seen this alert before,
- * return that we have previously alerted on original packet.
- */
- if ( st->alerts[i].gid == gid &&
- st->alerts[i].sid == sid )
+ if (SEQ_GEQ(ss->seq,start_seq) && SEQ_LT(ss->seq, end_seq))
{
- return -1;
+ DAQ_PktHdr_t pkth;
+ pkth.ts.tv_sec = ss->tv.tv_sec;
+ pkth.ts.tv_usec = ss->tv.tv_usec;
+ pkth.caplen = ss->caplen;
+ pkth.pktlen = ss->pktlen;
+
+ if (callback(&pkth, ss->pkt, ss->data, ss->seq, userdata) != 0)
+ return -1;
+
+ packets++;
}
+ else
+ break;
}
- return iRet;
+ return packets;
}
-int StreamUpdateSessionAlertTcp(
- Flow* lwssn, Packet* p,
- uint32_t gid, uint32_t sid,
- uint32_t event_id, uint32_t event_second)
+int TcpSession::update_alert(
+ Packet *p, uint32_t gid, uint32_t sid, uint32_t event_id, uint32_t event_second)
{
- StreamTracker* st;
+ TcpTracker *st;
int i;
uint32_t seq_num;
- TcpSession* tcpssn = (TcpSession*)lwssn->session;
- if (sfip_equals(p->ptrs.ip_api.get_src(), &tcpssn->flow->client_ip))
- {
- st = &tcpssn->server;
- }
+ if (sfip_equals(p->ptrs.ip_api.get_src(), &flow->client_ip))
+ st = &server;
else
- {
- st = &tcpssn->client;
- }
+ st = &client;
seq_num = GET_PKT_SEQ(p);
return -1;
}
-void StreamSetExtraDataTcp(Flow* lwssn, Packet* p, uint32_t xid)
+void TcpSession::set_extra_data(Packet* p, uint32_t xid)
{
- StreamTracker* st;
- TcpSession* tcpssn = (TcpSession*)lwssn->session;
+ TcpTracker *st;
- if (sfip_equals(p->ptrs.ip_api.get_src(),&tcpssn->flow->client_ip))
- st = &tcpssn->server;
+ if (sfip_equals(p->ptrs.ip_api.get_src(),&flow->client_ip))
+ st = &server;
else
- st = &tcpssn->client;
+ st = &client;
st->xtradata_mask |= BIT(xid);
}
-void StreamClearExtraDataTcp(Flow* lwssn, Packet* p, uint32_t xid)
+void TcpSession::clear_extra_data(Packet* p, uint32_t xid)
{
- StreamTracker* st;
- TcpSession* tcpssn = (TcpSession*)lwssn->session;
+ TcpTracker *st;
- if (sfip_equals(p->ptrs.ip_api.get_src(),&tcpssn->flow->client_ip))
- st = &tcpssn->server;
+ if (sfip_equals(p->ptrs.ip_api.get_src(),&flow->client_ip))
+ st = &server;
else
- st = &tcpssn->client;
+ st = &client;
if ( xid )
st->xtradata_mask &= ~BIT(xid);
st->xtradata_mask = 0;
}
-char StreamGetReassemblyDirectionTcp(Flow* lwssn)
+uint8_t TcpSession::get_reassembly_direction()
{
- char dir = SSN_DIR_NONE;
- TcpSession* tcpssn = NULL;
-
- if (!lwssn)
- return SSN_DIR_NONE;
+ uint8_t dir = SSN_DIR_NONE;
- tcpssn = (TcpSession*)lwssn->session;
-
- if ( tcpssn->server.flush_policy != STREAM_FLPOLICY_IGNORE )
+ if ( server.flush_policy != STREAM_FLPOLICY_IGNORE )
{
dir |= SSN_DIR_FROM_CLIENT;
}
- if ( tcpssn->client.flush_policy != STREAM_FLPOLICY_IGNORE )
+ if ( client.flush_policy != STREAM_FLPOLICY_IGNORE )
{
dir |= SSN_DIR_FROM_SERVER;
}
return dir;
}
-bool StreamGetReassemblyFlushPolicyTcp(Flow* lwssn, char dir)
-{
- TcpSession* tcpssn = NULL;
-
- if (!lwssn)
- return false;
-
- tcpssn = (TcpSession*)lwssn->session;
-
- if (dir & SSN_DIR_FROM_CLIENT)
- {
- return (char)tcpssn->client.flush_policy != STREAM_FLPOLICY_IGNORE;
- }
-
- if (dir & SSN_DIR_FROM_SERVER)
- {
- return (char)tcpssn->server.flush_policy != STREAM_FLPOLICY_IGNORE;
- }
- return false;
-}
-
-char StreamIsStreamSequencedTcp(Flow* lwssn, char dir)
+bool TcpSession::is_sequenced(uint8_t dir)
{
- TcpSession* tcpssn = NULL;
-
- if (!lwssn)
- return 1;
-
- tcpssn = (TcpSession*)lwssn->session;
-
if (dir & SSN_DIR_FROM_CLIENT)
{
- if ( tcpssn->server.flags & (TF_MISSING_PREV_PKT|TF_MISSING_PKT) )
- return 0;
+ if ( server.flags & (TF_MISSING_PREV_PKT|TF_MISSING_PKT) )
+ return false;
}
if (dir & SSN_DIR_FROM_SERVER)
{
- if ( tcpssn->client.flags & (TF_MISSING_PREV_PKT|TF_MISSING_PKT) )
- return 0;
+ if ( client.flags & (TF_MISSING_PREV_PKT|TF_MISSING_PKT) )
+ return false;
}
- return 1;
+ return true;
}
-/* This will falsly return SSN_MISSING_BEFORE on the first reassembed
+/* This will falsely return SSN_MISSING_BEFORE on the first reassembed
* packet if reassembly for this direction was set mid-session */
-int StreamMissingInReassembledTcp(Flow* lwssn, char dir)
+uint8_t TcpSession::missing_in_reassembled(uint8_t dir)
{
- TcpSession* tcpssn = NULL;
-
- if (!lwssn)
- return SSN_MISSING_NONE;
-
- tcpssn = (TcpSession*)lwssn->session;
-
if (dir & SSN_DIR_FROM_CLIENT)
{
- if ((tcpssn->server.flags & TF_MISSING_PKT) &&
- (tcpssn->server.flags & TF_MISSING_PREV_PKT))
+ if ((server.flags & TF_MISSING_PKT) &&
+ (server.flags & TF_MISSING_PREV_PKT))
return SSN_MISSING_BOTH;
- else if (tcpssn->server.flags & TF_MISSING_PREV_PKT)
+ else if (server.flags & TF_MISSING_PREV_PKT)
return SSN_MISSING_BEFORE;
- else if (tcpssn->server.flags & TF_MISSING_PKT)
+ else if (server.flags & TF_MISSING_PKT)
return SSN_MISSING_AFTER;
}
else if (dir & SSN_DIR_FROM_SERVER)
{
- if ((tcpssn->client.flags & TF_MISSING_PKT) &&
- (tcpssn->client.flags & TF_MISSING_PREV_PKT))
+ if ((client.flags & TF_MISSING_PKT) &&
+ (client.flags & TF_MISSING_PREV_PKT))
return SSN_MISSING_BOTH;
- else if (tcpssn->client.flags & TF_MISSING_PREV_PKT)
+ else if (client.flags & TF_MISSING_PREV_PKT)
return SSN_MISSING_BEFORE;
- else if (tcpssn->client.flags & TF_MISSING_PKT)
+ else if (client.flags & TF_MISSING_PKT)
return SSN_MISSING_AFTER;
}
return SSN_MISSING_NONE;
}
-char StreamPacketsMissingTcp(Flow* lwssn, char dir)
+bool TcpSession::are_packets_missing(uint8_t dir)
{
- TcpSession* tcpssn = NULL;
-
- if (!lwssn)
- return 0;
-
- tcpssn = (TcpSession*)lwssn->session;
-
if (dir & SSN_DIR_FROM_CLIENT)
{
- if (tcpssn->server.flags & TF_PKT_MISSED)
- return 1;
+ if (server.flags & TF_PKT_MISSED)
+ return true;
}
if (dir & SSN_DIR_FROM_SERVER)
{
- if (tcpssn->client.flags & TF_PKT_MISSED)
- return 1;
- }
-
- return 0;
-}
-
-//-------------------------------------------------------------------------
-// TcpSession methods
-//-------------------------------------------------------------------------
-
-TcpSession::TcpSession(Flow* flow) : Session(flow)
-{
- lws_init = tcp_init = false;
-}
-
-TcpSession::~TcpSession()
-{
- if ( tcp_init )
- TcpSessionClear(flow, (TcpSession*)flow->session, 1);
-}
-
-void TcpSession::reset()
-{
- if ( tcp_init )
- TcpSessionClear(flow, (TcpSession*)flow->session, 2);
-}
-
-bool TcpSession::setup(Packet*)
-{
- // FIXIT-L this it should not be necessary to reset here
- reset();
-
- lws_init = tcp_init = false;
- event_mask = 0;
- ecn = 0;
-
- memset(&client, 0, sizeof(client));
- memset(&server, 0, sizeof(server));
-
-#ifdef HAVE_DAQ_ADDRESS_SPACE_ID
- ingress_index = egress_index = 0;
- ingress_group = egress_group = 0;
- daq_flags = address_space_id = 0;
-#endif
-
- tcpStats.sessions++;
- return true;
-}
-
-void TcpSession::cleanup()
-{
- // this flushes data and then calls TcpSessionClear()
- TcpSessionCleanup(flow, 1);
-}
-
-// FIXIT-L this was originally called by Stream::drop_packet()
-// which is now calling Session::clear()
-void TcpSession::clear()
-{
- if ( tcp_init )
- // this does NOT flush data
- TcpSessionClear(flow, this, 1);
-}
-
-void TcpSession::restart(Packet* p)
-{
- StreamTracker* talker, * listener;
- TcpSession* tcpssn = (TcpSession*)p->flow->session;
-
- if ( p->packet_flags & PKT_FROM_SERVER )
- {
- talker = &tcpssn->server;
- listener = &tcpssn->client;
- }
- else
- {
- talker = &tcpssn->client;
- listener = &tcpssn->server;
+ if (client.flags & TF_PKT_MISSED)
+ return true;
}
- // FIXTHIS-H on data / on ack must be based on flush policy
- if ( p->dsize > 0 )
- CheckFlushPolicyOnData(this, talker, listener, p);
-
- if ( p->ptrs.tcph->is_ack() )
- CheckFlushPolicyOnAck(this, talker, listener, p);
+ return false;
}
void TcpSession::update_direction(
{
sfip_t tmpIp;
uint16_t tmpPort;
- StreamTracker tmpTracker;
+ TcpTracker tmpTracker;
if (sfip_equals(&flow->client_ip, ip) && (flow->client_port == port))
{
#ifdef HAVE_DAQ_ADDRESS_SPACE_ID
SwapPacketHeaderFoo(this);
#endif
- memcpy(&tmpTracker, &client, sizeof(StreamTracker));
- memcpy(&client, &server, sizeof(StreamTracker));
- memcpy(&server, &tmpTracker, sizeof(StreamTracker));
+ memcpy(&tmpTracker, &client, sizeof(TcpTracker));
+ memcpy(&client, &server, sizeof(TcpTracker));
+ memcpy(&server, &tmpTracker, sizeof(TcpTracker));
}
/*
SetupTcpDataBlock(&tdb, p);
StreamTcpConfig* config = get_tcp_cfg(flow->ssn_server);
- TcpSession* tcpssn = (TcpSession*)flow->session;
- if ( !tcpssn->lws_init )
+ if ( !lws_init )
{
// FIXIT most of this now looks out of place or redundant
if ( config->require_3whs() )
"Handshake, but failed to retrieve session object "
"for non SYN packet.\n"); );
- if ( !p->ptrs.tcph->is_rst() && !(tcpssn->event_mask & EVENT_NO_3WHS) )
+ if ( !p->ptrs.tcph->is_rst() && !(event_mask & EVENT_NO_3WHS) )
{
EventNo3whs();
- tcpssn->event_mask |= EVENT_NO_3WHS;
+ event_mask |= EVENT_NO_3WHS;
}
MODULE_PROFILE_END(s5TcpPerfStats);
return 0;
}
}
- tcpssn->lws_init = true;
+ lws_init = true;
}
/*
* Check if the session is expired.
bool TcpSession::add_alert(Packet* p, uint32_t gid, uint32_t sid)
{
- return StreamAddSessionAlertTcp(p->flow, p, gid, sid) != 0;
+ TcpTracker *st;
+ StreamAlertInfo* ai;
+
+ if (sfip_equals(p->ptrs.ip_api.get_src(),&flow->client_ip))
+ st = &server;
+ else
+ st = &client;
+
+ if (st->alert_count >= MAX_SESSION_ALERTS)
+ return false;
+
+ ai = st->alerts + st->alert_count;
+ ai->gid = gid;
+ ai->sid = sid;
+ ai->seq = GET_PKT_SEQ(p);
+
+ if ( p->ptrs.tcph->th_flags & TH_FIN )
+ ai->seq--;
+
+ st->alert_count++;
+
+ return true;
}
bool TcpSession::check_alerted(Packet* p, uint32_t gid, uint32_t sid)
{
- return StreamCheckSessionAlertTcp(p->flow, p, gid, sid) != 0;
+ /* If this is not a rebuilt packet, no need to check further */
+ if ( !(p->packet_flags & PKT_REBUILT_STREAM) )
+ return false;
+
+ TcpTracker *st;
+
+ if (sfip_equals(p->ptrs.ip_api.get_src(), &flow->client_ip))
+ st = &server;
+ else
+ st = &client;
+
+ for ( int i = 0; i < st->alert_count; i++ )
+ {
+ /* This is a rebuilt packet and if we've seen this alert before,
+ * return that we have previously alerted on original packet.
+ */
+ if ( st->alerts[i].gid == gid &&
+ st->alerts[i].sid == sid )
+ {
+ return true;
+ }
+ }
+
+ return false;
}
void TcpSession::flush()
#define TCP_SESSION_H
#include "stream_tcp.h"
-#include "stream_paf.h"
+#include "stream/paf.h"
#include "flow/session.h"
/* Only track a maximum number of alerts per session */
//
// -- event id and second are added to the session alert trackers so that
// the extra data can be correlated with events
-// -- event id and second are not available when StreamAddSessionAlertTcp
+// -- event id and second are not available when check_alerted()
// is called; u2 calls StreamUpdateSessionAlertTcp as events are logged
// to set these fields
//-------------------------------------------------------------------------
};
//-----------------------------------------------------------------
-// we make a lot of StreamSegments, StreamTrackers, and TcpSessions
+// we make a lot of TcpSegments, TcpTrackers, and TcpSessions
// so they are organized by member size/alignment requirements to
// minimize unused space in the structs.
// ... however, use of padding below is critical, adjust if needed
//-----------------------------------------------------------------
-struct StreamSegment
+struct TcpSegment
{
uint8_t* data;
uint8_t* payload;
- StreamSegment* prev;
- StreamSegment* next;
+ TcpSegment *prev;
+ TcpSegment *next;
struct timeval tv;
uint32_t caplen;
STREAM_FLPOLICY_ON_DATA, /* protocol aware ips */
};
-struct StreamTracker
+struct TcpTracker
{
StateMgr s_mgr; /* state tracking goodies */
class StreamSplitter* splitter;
FlushPolicy flush_policy;
- // this is intended to be private to s5_paf but is included
+ // this is intended to be private to paf but is included
// directly to avoid the need for allocation; do not directly
// manipulate within this module.
PAF_State paf_state; // for tracking protocol aware flushing
- StreamAlertInfo alerts[MAX_SESSION_ALERTS]; /* history of alerts */
-
StreamTcpConfig* config;
- StreamSegment* seglist; /* first queued segment */
- StreamSegment* seglist_tail; /* last queued segment */
+ TcpSegment *seglist; /* first queued segment */
+ TcpSegment *seglist_tail; /* last queued segment */
// FIXIT-P seglist_base_seq is the sequence number to flush from
// and is valid even when seglist is empty. seglist_next is
// the segment to flush from and is set per packet. should keep
// up to date.
- StreamSegment* seglist_next;
+ TcpSegment* seglist_next;
/* Local for these variables means the local part of the connection. For
- * example, if this particular StreamTracker was tracking the client side
+ * example, if this particular TcpTracker was tracking the client side
* of a connection, the l_unackd value would represent the client side of
* the connection's last unacked sequence number
*/
uint16_t wscale; /* window scale setting */
uint16_t mss; /* max segment size */
- uint8_t mac_addr[6];
- uint8_t flags; /* bitmap flags (TF_xxx) */
+ uint8_t mac_addr[6];
+ uint8_t flags; /* bitmap flags (TF_xxx) */
- uint8_t alert_count; /* number alerts stored (up to MAX_SESSION_ALERTS) */
+ uint8_t alert_count; /* number alerts stored (up to MAX_SESSION_ALERTS) */
+ StreamAlertInfo alerts[MAX_SESSION_ALERTS]; /* history of alerts */
};
// FIXIT-L session tracking must be split from reassembly
bool setup(Packet*) override;
int process(Packet*) override;
-
- void update_direction(char dir, const sfip_t*, uint16_t port) override;
-
void clear() override;
void cleanup() override;
-
- void reset();
void restart(Packet*) override;
+ void update_direction(char dir, const sfip_t*, uint16_t port) override;
+
bool add_alert(Packet*, uint32_t gid, uint32_t sid) override;
bool check_alerted(Packet*, uint32_t gid, uint32_t sid) override;
+ int update_alert(
+ Packet*, uint32_t /*gid*/, uint32_t /*sid*/,
+ uint32_t /*event_id*/, uint32_t /*event_second*/) override;
+
+ void flush_client(Packet*) override;
+ void flush_server(Packet*) override;
+ void flush_talker(Packet*) override;
+ void flush_listener(Packet*) override;
+
+ void set_splitter(bool /*c2s*/, StreamSplitter*) override;
+ StreamSplitter* get_splitter(bool /*c2s*/) override;
+
+ void set_extra_data(Packet*, uint32_t /*flag*/) override;
+ void clear_extra_data(Packet*, uint32_t /*flag*/) override;
+
+ int get_rebuilt_packets(Packet*, PacketIterator, void* /*userdata*/) override;
+ int get_segments(Packet*, StreamSegmentIterator, void* /*userdata*/) override;
+
+ bool is_sequenced(uint8_t /*dir*/) override;
+ bool are_packets_missing(uint8_t /*dir*/) override;
+
+ uint8_t get_reassembly_direction() override;
+ uint8_t missing_in_reassembled(uint8_t /*dir*/) override;
+
+ void reset();
void flush();
void start_proxy();
public:
- StreamTracker client;
- StreamTracker server;
+ TcpTracker client;
+ TcpTracker server;
#ifdef HAVE_DAQ_ADDRESS_SPACE_ID
int32_t ingress_index; /* Index of the inbound interface. */
--- /dev/null
+
+add_library( stream_user STATIC
+ user_module.cc
+ user_module.h
+ user_session.cc
+ user_session.h
+ stream_user.cc
+ stream_user.h
+)
--- /dev/null
+AUTOMAKE_OPTIONS=foreign no-dependencies
+
+noinst_LIBRARIES = libstream_user.a
+
+libstream_user_a_SOURCES = \
+user_module.cc \
+user_module.h \
+user_session.cc \
+user_session.h \
+stream_user.cc \
+stream_user.h
+
+AM_CXXFLAGS = @AM_CXXFLAGS@
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// stream_user.cc author Russ Combs <rucombs@cisco.com>
+
+#include "stream_user.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <assert.h>
+
+#include "user_module.h"
+#include "user_session.h"
+#include "log/messages.h"
+#include "protocols/packet.h"
+
+//-------------------------------------------------------------------------
+// helpers
+//-------------------------------------------------------------------------
+
+StreamUserConfig::StreamUserConfig()
+{
+ session_timeout = 60;
+}
+
+static void user_show (StreamUserConfig* pc)
+{
+ LogMessage("Stream user config:\n");
+ LogMessage(" Timeout: %d seconds\n", pc->session_timeout);
+}
+
+//-------------------------------------------------------------------------
+// inspector stuff
+//-------------------------------------------------------------------------
+
+class StreamUser : public Inspector
+{
+public:
+ StreamUser(StreamUserConfig*);
+ ~StreamUser();
+
+ void show(SnortConfig*) override;
+
+ void eval(Packet*) override;
+
+public:
+ StreamUserConfig* config;
+};
+
+StreamUser::StreamUser (StreamUserConfig* c)
+{
+ config = c;
+}
+
+StreamUser::~StreamUser()
+{
+ delete config;
+}
+
+void StreamUser::show(SnortConfig*)
+{
+ user_show(config);
+}
+
+void StreamUser::eval(Packet*)
+{
+ // session::process() instead
+ assert(false);
+}
+
+StreamUserConfig* get_user_cfg(Inspector* ins)
+{
+ assert(ins);
+ return ((StreamUser*)ins)->config;
+}
+
+//-------------------------------------------------------------------------
+// api stuff
+//-------------------------------------------------------------------------
+
+static Module* mod_ctor()
+{ return new StreamUserModule; }
+
+static void mod_dtor(Module* m)
+{ delete m; }
+
+static Inspector* user_ctor(Module* m)
+{
+ StreamUserModule* mod = (StreamUserModule*)m;
+ return new StreamUser(mod->get_data());
+}
+
+static void user_dtor(Inspector* p)
+{
+ delete p;
+}
+
+static Session* user_ssn(Flow* lws)
+{
+ return new UserSession(lws);
+}
+
+static const InspectApi user_api =
+{
+ {
+ PT_INSPECTOR,
+ sizeof(InspectApi),
+ INSAPI_VERSION,
+ 0,
+ API_RESERVED,
+ API_OPTIONS,
+ MOD_NAME,
+ MOD_HELP,
+ mod_ctor,
+ mod_dtor
+ },
+ IT_STREAM,
+ (unsigned)PktType::USER,
+ nullptr, // buffers
+ nullptr, // service
+ nullptr, // pinit
+ nullptr, // pterm
+ nullptr, // tinit
+ nullptr, // tterm
+ user_ctor,
+ user_dtor,
+ user_ssn,
+ nullptr // reset
+};
+
+const BaseApi* nin_stream_user = &user_api.base;
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// stream_user.h author Russ Combs <rucombs@cisco.com>
+
+#ifndef STREAM_USER_H
+#define STREAM_USER_H
+
+#include "flow/flow.h"
+
+struct StreamUserConfig
+{
+ uint32_t session_timeout;
+
+ StreamUserConfig();
+};
+
+StreamUserConfig* get_user_cfg(Inspector*);
+
+#endif
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// user_module.cc author Russ Combs <rucombs@cisco.com>
+
+#include "user_module.h"
+
+#include <string>
+using namespace std;
+
+#include "stream_user.h"
+#include "main/snort_config.h"
+#include "stream/stream.h"
+
+//-------------------------------------------------------------------------
+// stream_user module
+//-------------------------------------------------------------------------
+
+static const Parameter s_params[] =
+{
+ { "session_timeout", Parameter::PT_INT, "1:86400", "30",
+ "session tracking timeout" },
+
+ { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+StreamUserModule::StreamUserModule() :
+ Module(MOD_NAME, MOD_HELP, s_params)
+{
+ config = nullptr;
+}
+
+StreamUserModule::~StreamUserModule()
+{
+ if ( config )
+ delete config;
+}
+
+StreamUserConfig* StreamUserModule::get_data()
+{
+ StreamUserConfig* temp = config;
+ config = nullptr;
+ return temp;
+}
+
+bool StreamUserModule::set(const char*, Value& v, SnortConfig*)
+{
+ if ( v.is("session_timeout") )
+ config->session_timeout = v.get_long();
+
+ else
+ return false;
+
+ return true;
+}
+
+bool StreamUserModule::begin(const char*, int, SnortConfig*)
+{
+ if ( !config )
+ config = new StreamUserConfig;
+
+ return true;
+}
+
+bool StreamUserModule::end(const char*, int, SnortConfig*)
+{
+ return true;
+}
+
+#if 0
+const PegInfo* StreamUserModule::get_pegs() const
+{ return user_pegs; }
+
+PegCount* StreamUserModule::get_counts() const
+{ return (PegCount*)&user_stats; }
+#endif
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// user_module.h author Russ Combs <rucombs@cisco.com>
+
+#ifndef USER_MODULE_H
+#define USER_MODULE_H
+
+#include "snort_types.h"
+#include "framework/module.h"
+#include "main/thread.h"
+#include "stream/stream.h"
+
+struct SnortConfig;
+
+extern const PegInfo user_pegs[];
+extern THREAD_LOCAL struct UserStats user_stats;
+extern THREAD_LOCAL ProfileStats user_perf_stats;
+
+//-------------------------------------------------------------------------
+// stream_user module
+//-------------------------------------------------------------------------
+
+#define MOD_NAME "stream_user"
+#define MOD_HELP "stream inspector for user flow tracking and reassembly "
+
+struct StreamUserConfig;
+
+class StreamUserModule : public Module
+{
+public:
+ StreamUserModule();
+ ~StreamUserModule();
+
+ bool set(const char*, Value&, SnortConfig*) override;
+ bool begin(const char*, int, SnortConfig*) override;
+ bool end(const char*, int, SnortConfig*) override;
+
+#if 0
+ const PegInfo* get_pegs() const override;
+ PegCount* get_counts() const override;
+#endif
+
+ StreamUserConfig* get_data();
+
+private:
+ StreamUserConfig* config;
+};
+
+#endif
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// user_session.cc author Russ Combs <rucombs@cisco.com>
+
+#include "user_session.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "stream_user.h"
+#include "user_module.h"
+#include "stream/stream.h"
+#include "stream/stream_splitter.h"
+#include "stream/paf.h"
+#include "perf_monitor/perf.h"
+#include "flow/flow_control.h"
+#include "sfip/sf_ip.h"
+#include "time/profiler.h"
+#include "main/snort.h"
+
+THREAD_LOCAL ProfileStats user_perf_stats;
+
+// we always get exactly one copy of user data in order
+// maintain "seg"list of user data stream
+// run user data through paf
+
+//-------------------------------------------------------------------------
+// basic stuff
+//-------------------------------------------------------------------------
+
+UserSegment::UserSegment(const uint8_t* p, unsigned n)
+{
+ data = new uint8_t[n];
+ memcpy(data, p, n);
+ len = n;
+ offset = 0;
+}
+
+UserSegment::~UserSegment()
+{
+ delete[] data;
+}
+
+UserTracker::UserTracker()
+{ init(); }
+
+UserTracker::~UserTracker()
+{ term(); }
+
+void UserTracker::init()
+{
+ paf_clear(&paf_state);
+ splitter = nullptr;
+ total = 0;
+}
+
+void UserTracker::term()
+{
+ delete splitter;
+ splitter = nullptr;
+}
+
+//-------------------------------------------------------------------------
+// tracker packet stuff
+//-------------------------------------------------------------------------
+
+void UserTracker::detect(const Packet* p, const StreamBuffer* sb, uint32_t flags)
+{
+ Packet up;
+ up.reset();
+
+ up.pkth = p->pkth;
+ up.ptrs = p->ptrs;
+ up.flow = p->flow;
+ up.data = sb->data;
+ up.dsize = sb->length;
+
+ up.proto_bits = p->proto_bits;
+ up.application_protocol_ordinal = p->application_protocol_ordinal;
+
+ up.packet_flags = flags | PKT_REBUILT_STREAM;
+ up.packet_flags |= (p->packet_flags & (PKT_FROM_CLIENT|PKT_FROM_SERVER));
+ up.packet_flags |= (p->packet_flags & (PKT_STREAM_EST|PKT_STREAM_UNEST_UNI));
+
+ //printf("user detect[%d]\n", up.dsize);
+ Snort::detect_rebuilt_packet(&up);
+}
+
+int UserTracker::scan(Packet* p, uint32_t& flags)
+{
+ UserSegment* last = seg_list.back();
+ flags = p->packet_flags & (PKT_FROM_CLIENT|PKT_FROM_SERVER);
+ //printf("user scan[%d]\n", last->len);
+
+ int32_t flush_amt = paf_check(
+ splitter, &paf_state, p->flow, last->data, last->len, total, paf_state.seq, &flags);
+
+ if ( flush_amt > 0 )
+ {
+ if ( !splitter->is_paf() && total > (unsigned)flush_amt )
+ {
+ paf_jump(&paf_state, total - flush_amt);
+ return total;
+ }
+ }
+ return flush_amt;
+}
+
+void UserTracker::flush(Packet* p, unsigned flush_amt, uint32_t flags)
+{
+ unsigned bytes_flushed = 0;
+ const StreamBuffer* sb = nullptr;
+ //printf("user flush[%d]\n", flush_amt);
+ uint32_t rflags = flags & ~PKT_PDU_TAIL;
+
+ while ( !seg_list.empty() and flush_amt )
+ {
+ UserSegment* us = seg_list.front();
+ const uint8_t* data = us->data + us->offset;
+ unsigned bytes_copied = 0;
+
+ if ( us->len == flush_amt )
+ rflags |= (flags & PKT_PDU_TAIL);
+
+ //printf("user reassemble[%d]\n", us->len);
+ sb = splitter->reassemble(
+ p->flow, flush_amt, bytes_flushed, data, us->len, rflags, bytes_copied);
+
+ bytes_flushed += bytes_copied;
+ rflags &= ~PKT_PDU_HEAD;
+
+ if ( sb )
+ detect(p, sb, flags);
+
+ if ( us->len == bytes_copied )
+ {
+ total -= us->len;
+ flush_amt -= us->len;
+ seg_list.pop_front();
+ delete us;
+ }
+ else
+ {
+ total -= bytes_copied;
+ us->shift(bytes_copied);
+ flush_amt = 0;
+ }
+ }
+}
+
+void UserTracker::process(Packet* p)
+{
+ uint32_t flags = 0;
+ int flush_amt = scan(p, flags);
+
+ while ( flush_amt >= 0 )
+ {
+ unsigned amt = (unsigned)flush_amt;
+ assert(total >= amt);
+
+ flush(p, amt, flags);
+
+ if ( total )
+ flush_amt = scan(p, flags);
+ else
+ break;
+ }
+}
+
+void UserTracker::add_data(Packet* p)
+{
+ //printf("user add[%d]\n", p->dsize);
+ seg_list.push_back(new UserSegment(p->data, p->dsize));
+ total += p->dsize;
+ process(p);
+}
+
+//-------------------------------------------------------------------------
+// private user session methods
+// may need additional refactoring
+//-------------------------------------------------------------------------
+
+void UserSession::start(Packet* p, Flow* flow)
+{
+ Inspector* ins = flow->gadget;
+
+ if ( !ins )
+ ins = flow->clouseau;
+
+ if ( ins )
+ {
+ set_splitter(true, ins->get_splitter(true));
+ set_splitter(false, ins->get_splitter(false));
+ }
+ else
+ {
+ set_splitter(true, new AtomSplitter(true));
+ set_splitter(false, new AtomSplitter(false));
+ }
+
+ {
+ flow->protocol = p->type();
+
+ if (flow->ssn_state.session_flags & SSNFLAG_RESET)
+ flow->ssn_state.session_flags &= ~SSNFLAG_RESET;
+
+ if ( (flow->ssn_state.session_flags & SSNFLAG_CLIENT_SWAP) &&
+ !(flow->ssn_state.session_flags & SSNFLAG_CLIENT_SWAPPED) )
+ {
+ sfip_t ip = flow->client_ip;
+ uint16_t port = flow->client_port;
+
+ flow->client_ip = flow->server_ip;
+ flow->server_ip = ip;
+
+ flow->client_port = flow->server_port;
+ flow->server_port = port;
+
+ if ( !flow->two_way_traffic() )
+ {
+ if ( flow->ssn_state.session_flags & SSNFLAG_SEEN_CLIENT )
+ {
+ flow->ssn_state.session_flags ^= SSNFLAG_SEEN_CLIENT;
+ flow->ssn_state.session_flags |= SSNFLAG_SEEN_SERVER;
+ }
+ else if ( flow->ssn_state.session_flags & SSNFLAG_SEEN_SERVER )
+ {
+ flow->ssn_state.session_flags ^= SSNFLAG_SEEN_SERVER;
+ flow->ssn_state.session_flags |= SSNFLAG_SEEN_CLIENT;
+ }
+ }
+ flow->ssn_state.session_flags |= SSNFLAG_CLIENT_SWAPPED;
+ }
+#if 0
+ // FIXIT-L TBD
+ //flow->set_expire(p, dstPolicy->session_timeout);
+
+ // add user flavor to perf stats?
+ AddStreamSession(
+ &sfBase, flow->session_state & STREAM_STATE_MIDSTREAM ? SSNFLAG_MIDSTREAM : 0);
+
+ StreamUpdatePerfBaseState(&sfBase, tmp->flow, TCP_STATE_SYN_SENT);
+
+ EventInternal(INTERNAL_EVENT_SESSION_ADD);
+#endif
+ }
+}
+
+void UserSession::end(Packet*, Flow*)
+{
+ delete client.splitter;
+ delete server.splitter;
+
+ client.splitter = nullptr;
+ server.splitter = nullptr;
+}
+
+void UserSession::update(Packet* p, Flow* flow)
+{
+ if ( p->ptrs.sp and p->ptrs.dp )
+ p->packet_flags |= PKT_STREAM_EST;
+ else
+ p->packet_flags |= PKT_STREAM_UNEST_UNI;
+
+ if ( !(flow->ssn_state.session_flags & SSNFLAG_ESTABLISHED) )
+ {
+ if ( p->packet_flags & PKT_FROM_CLIENT )
+ flow->ssn_state.session_flags |= SSNFLAG_SEEN_CLIENT;
+ else
+ flow->ssn_state.session_flags |= SSNFLAG_SEEN_SERVER;
+
+ if ( (flow->ssn_state.session_flags & SSNFLAG_SEEN_CLIENT) &&
+ (flow->ssn_state.session_flags & SSNFLAG_SEEN_SERVER) )
+ {
+ flow->ssn_state.session_flags |= SSNFLAG_ESTABLISHED;
+
+ flow->set_ttl(p, false);
+ }
+ }
+
+ StreamUserConfig* pc = get_user_cfg(flow->ssn_server);
+ flow->set_expire(p, pc->session_timeout);
+}
+
+void UserSession::restart(Packet* p)
+{
+ bool c2s = p->packet_flags & PKT_FROM_CLIENT;
+ UserTracker& ut = c2s ? server : client;
+ std::list<UserSegment*> tmp = std::move(ut.seg_list);
+
+ ut.total = 0;
+
+ while ( !tmp.empty() )
+ {
+ UserSegment* us = tmp.front();
+ tmp.pop_front();
+ ut.seg_list.push_back(us);
+ ut.total += us->len;
+ ut.process(p);
+ }
+}
+
+//-------------------------------------------------------------------------
+// UserSession methods
+//-------------------------------------------------------------------------
+
+UserSession::UserSession(Flow* flow) : Session(flow) { }
+
+UserSession::~UserSession() { }
+
+bool UserSession::setup(Packet*)
+{
+ client.init();
+ server.init();
+
+#ifdef ENABLE_EXPECTED_USER
+ if ( flow_con->expected_session(flow, p))
+ {
+ MODULE_PROFILE_END(user_perf_stats);
+ return false;
+ }
+#endif
+ return true;
+}
+
+void UserSession::clear()
+{
+ client.term();
+ server.term();
+ flow->restart();
+}
+
+void UserSession::set_splitter(bool c2s, StreamSplitter* ss)
+{
+ UserTracker& ut = c2s ? server : client;
+
+ if ( ut.splitter )
+ delete ut.splitter;
+
+ ut.splitter = ss;
+
+ if ( ss )
+ paf_setup(&ut.paf_state);
+}
+
+StreamSplitter* UserSession::get_splitter(bool c2s)
+{
+ UserTracker& ut = c2s ? server : client;
+ return ut.splitter;
+}
+
+int UserSession::process(Packet* p)
+{
+ PROFILE_VARS;
+ MODULE_PROFILE_START(user_perf_stats);
+
+ if ( stream.expired_session(flow, p) )
+ {
+ flow->restart();
+ // FIXIT count user session timeouts here
+
+#ifdef ENABLE_EXPECTED_USER
+ if ( flow_con->expected_session(flow, p))
+ {
+ MODULE_PROFILE_END(user_perf_stats);
+ return 0;
+ }
+#endif
+ }
+
+ flow->set_direction(p);
+
+ if ( stream.blocked_session(flow, p) || stream.ignored_session(flow, p) )
+ {
+ MODULE_PROFILE_END(user_perf_stats);
+ return 0;
+ }
+
+ update(p, flow);
+
+ UserTracker& ut = p->from_client() ? server : client;
+
+ if ( p->ptrs.decode_flags & DECODE_SOF )
+ start(p, flow);
+
+ if ( p->data && p->dsize )
+ ut.add_data(p);
+
+ if ( p->ptrs.decode_flags & DECODE_EOF )
+ end(p, flow);
+
+ MODULE_PROFILE_END(user_perf_stats);
+ return 0;
+}
+
+//-------------------------------------------------------------------------
+// UserSession methods
+// FIXIT-L these are TBD after tcp is updated
+// some will be deleted, some refactored, some implemented
+//-------------------------------------------------------------------------
+
+void UserSession::update_direction(char /*dir*/, const sfip_t*, uint16_t /*port*/) { }
+
+bool UserSession::add_alert(Packet*, uint32_t /*gid*/, uint32_t /*sid*/) { return true; }
+bool UserSession::check_alerted(Packet*, uint32_t /*gid*/, uint32_t /*sid*/) { return false; }
+
+int UserSession::update_alert(
+ Packet*, uint32_t /*gid*/, uint32_t /*sid*/,
+ uint32_t /*event_id*/, uint32_t /*event_second*/)
+{ return 0; }
+
+void UserSession::flush_client(Packet*) { }
+void UserSession::flush_server(Packet*) { }
+void UserSession::flush_talker(Packet*) { }
+void UserSession::flush_listener(Packet*) { }
+
+void UserSession::set_extra_data(Packet*, uint32_t /*flag*/) { }
+void UserSession::clear_extra_data(Packet*, uint32_t /*flag*/) { }
+
+int UserSession::get_rebuilt_packets(Packet*, PacketIterator, void* /*userdata*/)
+{ return 0; }
+
+int UserSession::get_segments(Packet*, StreamSegmentIterator, void* /*userdata*/)
+{ return 0; }
+
+uint8_t UserSession::get_reassembly_direction()
+{ return SSN_DIR_NONE; }
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// user_session.h author Russ Combs <rucombs@cisco.com>
+
+#ifndef USER_SESSION_H
+#define USER_SESSION_H
+
+#include <assert.h>
+#include <list>
+
+#include "flow/session.h"
+#include "stream/paf.h"
+
+struct UserSegment
+{
+ UserSegment(const uint8_t*, unsigned);
+ ~UserSegment();
+
+ void shift(unsigned n)
+ {
+ assert(len >= n);
+ data += n;
+ len -= n;
+ }
+
+ uint8_t* data;
+ unsigned len;
+ unsigned offset;
+};
+
+struct UserTracker
+{
+ UserTracker();
+ ~UserTracker();
+
+ void init();
+ void term();
+
+ void process(Packet*);
+ void add_data(Packet*);
+ int scan(Packet*, uint32_t&);
+ void flush(struct Packet*, unsigned, uint32_t);
+ void detect(const struct Packet*, const struct StreamBuffer*, uint32_t);
+
+ std::list<UserSegment*> seg_list;
+ StreamSplitter* splitter;
+ PAF_State paf_state;
+ unsigned total;
+};
+
+class UserSession : public Session
+{
+public:
+ UserSession(Flow*);
+ ~UserSession();
+
+ bool setup(Packet*) override;
+ void clear() override;
+
+ int process(Packet*) override;
+
+ void set_splitter(bool c2s, StreamSplitter*) override;
+ StreamSplitter* get_splitter(bool c2s) override;
+ void restart(Packet*) override;
+
+ bool is_sequenced(uint8_t /*dir*/) override
+ { return true; }
+
+ bool are_packets_missing(uint8_t /*dir*/) override
+ { return false; }
+
+ uint8_t missing_in_reassembled(uint8_t /*dir*/) override
+ { return SSN_MISSING_NONE; }
+
+private:
+ void start(Packet*, Flow*);
+ void update(Packet*, Flow*);
+ void end(Packet*, Flow*);
+
+ void update_direction(char dir, const sfip_t*, uint16_t port) override;
+
+ bool add_alert(Packet*, uint32_t gid, uint32_t sid) override;
+ bool check_alerted(Packet*, uint32_t gid, uint32_t sid) override;
+
+ int update_alert(
+ Packet*, uint32_t gid, uint32_t sid, uint32_t event_id, uint32_t event_second) override;
+
+ void flush_client(Packet*) override;
+ void flush_server(Packet*) override;
+ void flush_talker(Packet*) override;
+ void flush_listener(Packet*) override;
+
+ void set_extra_data(Packet*, uint32_t flag) override;
+ void clear_extra_data(Packet*, uint32_t flag) override;
+
+ int get_rebuilt_packets(Packet*, PacketIterator, void* userdata) override;
+ int get_segments(Packet*, StreamSegmentIterator, void* userdata) override;
+
+ uint8_t get_reassembly_direction() override;
+
+public:
+ UserTracker client;
+ UserTracker server;
+};
+
+#endif
+
HostAttributeEntry* SFAT_LookupHostEntryBySrc(Packet* p)
{
- if (!p || !p->ptrs.ip_api.is_valid())
+ if (!p || !p->ptrs.ip_api.is_ip())
return NULL;
return SFAT_LookupHostEntryByIP(p->ptrs.ip_api.get_src());
HostAttributeEntry* SFAT_LookupHostEntryByDst(Packet* p)
{
- if (!p || !p->ptrs.ip_api.is_valid())
+ if (!p || !p->ptrs.ip_api.is_ip())
return NULL;
return SFAT_LookupHostEntryByIP(p->ptrs.ip_api.get_dst());
#include "filters/sfthreshold.h"
#include "time/ppm.h"
#include "time/profiler.h"
+#include "file_api/file_service.h"
#define STATS_SEPARATOR \
"--------------------------------------------------"
// FIXIT-L 2.0.4 introduces the retry verdict
// no way to reliably optionally leverage this with dynamic loaded daqs
+// FIXIT-L daq stats should be moved to sfdaq
+
#define MAX_SFDAQ_VERDICT 6
struct DAQStats
const PegInfo daq_names[] =
{
- { "pcaps", "total files processed" },
+ { "pcaps", "total files and interfaces processed" },
{ "received", "total packets received from DAQ" },
{ "analyzed", "total packets analyzed from DAQ" },
{ "dropped", "packets dropped" },
if ( gpc.total_alert_pkts == gpc.alert_pkts )
gpc.total_alert_pkts = 0;
+ //LogLabel("File Statistics");
+ print_file_stats();
+
LogLabel("Summary Statistics");
show_stats((PegCount*)&gpc, pc_names, array_size(pc_names)-1, "detection");