]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
russ:
authorRuss Combs <rucombs@cisco.com>
Sat, 16 May 2015 01:19:58 +0000 (21:19 -0400)
committerRuss Combs <rucombs@cisco.com>
Sat, 16 May 2015 01:19:58 +0000 (21:19 -0400)
-- added socket codec in extras
-- added DAQs for socket, user, and file in extras
-- added stream_user for use with proxy type traffic from socket and user
   DAQs
-- added stream_file for use with file DAQ for file type, signature, and
   inspection
-- refactor Session, StreamApi, and PAF
-- pulled DAQ README into manual
-- fix double loading of stream plugins
-- fix cmake build issues

159 files changed:
.gitignore
ChangeLog
configure.ac
doc/CMakeLists.txt
doc/Makefile.am
doc/config_changes.txt
doc/daq.txt [new file with mode: 0644]
doc/snort_manual.txt
extra/configure.ac
extra/src/CMakeLists.txt
extra/src/Makefile.am
extra/src/codecs/CMakeLists.txt
extra/src/codecs/Makefile.am
extra/src/codecs/daq204.diff [new file with mode: 0644]
extra/src/codecs/socket.cc [new file with mode: 0644]
extra/src/daqs/CMakeLists.txt [new file with mode: 0644]
extra/src/daqs/Makefile.am [new file with mode: 0644]
extra/src/daqs/daq_file.c [new file with mode: 0644]
extra/src/daqs/daq_socket.c [new file with mode: 0644]
extra/src/daqs/daq_socket.h [new file with mode: 0644]
extra/src/daqs/daq_user.c [new file with mode: 0644]
extra/src/inspectors/data_log.cc
extra/src/loggers/CMakeLists.txt
extra/src/loggers/Makefile.am
extra/src/loggers/log_user.cc [new file with mode: 0644]
snort.pc.in
src/CMakeLists.txt
src/Makefile.am
src/actions/act_react.cc
src/actions/act_replace.cc
src/codecs/ip/cd_esp.cc
src/codecs/ip/cd_gre.cc
src/codecs/ip/cd_icmp4.cc
src/codecs/ip/cd_icmp6.cc
src/codecs/ip/cd_ipv4.cc
src/codecs/ip/cd_ipv6.cc
src/codecs/ip/cd_pgm.cc
src/codecs/ip/cd_routing.cc
src/codecs/ip/cd_tcp.cc
src/codecs/ip/cd_udp.cc
src/codecs/link/cd_arp.cc
src/codecs/link/cd_mpls.cc
src/codecs/link/cd_ppp_encap.cc
src/codecs/link/cd_pppoe.cc
src/codecs/misc/CMakeLists.txt
src/codecs/misc/Makefile.am
src/codecs/misc/cd_gtp.cc
src/codecs/misc/cd_teredo.cc
src/codecs/root/cd_eth.cc
src/codecs/root/cd_wlan.cc
src/detection/detect.cc
src/detection/fpdetect.cc
src/detection/tag.cc
src/file_api/CMakeLists.txt
src/file_api/file_api.h
src/file_api/file_service.cc
src/file_api/file_service.h
src/file_api/libs/file_config.h
src/file_api/libs/file_identifier.cc
src/file_api/libs/file_lib.cc
src/file_api/libs/file_lib.h
src/filters/rate_filter.cc
src/flow/expect_cache.cc
src/flow/expect_cache.h
src/flow/flow.cc
src/flow/flow.h
src/flow/flow_control.cc
src/flow/flow_control.h
src/flow/flow_key.cc
src/flow/flow_key.h
src/flow/session.h
src/framework/codec.h
src/framework/decode_data.h
src/ips_options/ips_flow.cc
src/ips_options/ips_fragbits.cc
src/ips_options/ips_pcre.cc
src/ips_options/ips_replace.cc
src/ips_options/ips_tos.cc
src/ips_options/ips_ttl.cc
src/log/log.cc
src/log/log_text.cc
src/log/log_text.h
src/loggers/alert_fast.cc
src/loggers/alert_sf_socket.cc
src/loggers/alert_syslog.cc
src/loggers/unified2.cc
src/main/modules.cc
src/main/snort_config.h
src/main/snort_module.cc
src/managers/codec_manager.cc
src/managers/event_manager.cc
src/managers/inspector_manager.cc
src/network_inspectors/binder/bind_module.cc
src/network_inspectors/binder/binder.cc
src/network_inspectors/network_inspectors.cc
src/network_inspectors/normalize/normalize.cc
src/network_inspectors/perf_monitor/perf.cc
src/network_inspectors/port_scan/port_scan.cc
src/network_inspectors/port_scan/ps_detect.cc
src/packet_io/CMakeLists.txt
src/packet_io/active.cc
src/packet_io/sfdaq.cc
src/parser/config_file.cc
src/protocols/ip.cc
src/protocols/ip.h
src/protocols/packet.h
src/protocols/packet_manager.cc
src/search_engines/ac_bnfa.cc
src/search_engines/ac_bnfa_q.cc
src/search_engines/acsmx.cc
src/search_engines/acsmx2.cc
src/search_engines/bnfa_search.cc
src/service_inspectors/ftp_telnet/ftp.cc
src/service_inspectors/ftp_telnet/pp_ftp.cc
src/service_inspectors/http_inspect/hi_client.cc
src/service_inspectors/http_inspect/hi_main.cc
src/service_inspectors/http_inspect/hi_mi.cc
src/service_inspectors/http_inspect/hi_server.cc
src/service_inspectors/http_inspect/http_inspect.cc
src/service_inspectors/imap/imap.cc
src/service_inspectors/pop/pop.cc
src/service_inspectors/smtp/CMakeLists.txt
src/service_inspectors/smtp/smtp.cc
src/service_inspectors/wizard/wizard.cc
src/stream/CMakeLists.txt
src/stream/Makefile.am
src/stream/base/stream_base.cc
src/stream/base/stream_module.cc
src/stream/base/stream_module.h
src/stream/file/CMakeLists.txt [new file with mode: 0644]
src/stream/file/Makefile.am [new file with mode: 0644]
src/stream/file/file_module.cc [new file with mode: 0644]
src/stream/file/file_module.h [new file with mode: 0644]
src/stream/file/file_session.cc [new file with mode: 0644]
src/stream/file/file_session.h [new file with mode: 0644]
src/stream/file/stream_file.cc [new file with mode: 0644]
src/stream/file/stream_file.h [new file with mode: 0644]
src/stream/ip/ip_defrag.cc
src/stream/ip/ip_session.cc
src/stream/paf.cc [moved from src/stream/tcp/stream_paf.cc with 88% similarity]
src/stream/paf.h [moved from src/stream/tcp/stream_paf.h with 70% similarity]
src/stream/stream_api.cc
src/stream/stream_api.h
src/stream/stream_inspectors.cc
src/stream/tcp/CMakeLists.txt
src/stream/tcp/Makefile.am
src/stream/tcp/stream_tcp.h
src/stream/tcp/tcp_session.cc
src/stream/tcp/tcp_session.h
src/stream/user/CMakeLists.txt [new file with mode: 0644]
src/stream/user/Makefile.am [new file with mode: 0644]
src/stream/user/stream_user.cc [new file with mode: 0644]
src/stream/user/stream_user.h [new file with mode: 0644]
src/stream/user/user_module.cc [new file with mode: 0644]
src/stream/user/user_module.h [new file with mode: 0644]
src/stream/user/user_session.cc [new file with mode: 0644]
src/stream/user/user_session.h [new file with mode: 0644]
src/target_based/sftarget_reader.cc
src/utils/stats.cc

index c8f3795bf86bd947fa6a45059a80d0382b94e489..6056410cf59bdc3b99e618a61b4ccf4f447ad3a5 100644 (file)
@@ -1,4 +1,4 @@
-*.[oac]
+*.[oa]
 *.deps/
 *.la
 *.libs/
index f8a9e229de981630c3bc467776deb434ef03900a..afea4840697baf1e37ff87f19b8924b83be79dac 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+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
index 6efe3e270737b03529a7ce9268b2369442e6a05f..5ea6393929e7ef93e8b07690b3da6c1f92b3bfdd 100644 (file)
@@ -958,6 +958,8 @@ src/stream/ip/Makefile \
 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 \
index a5e522a032dd964801e983b2fbd92b550a0891a9..36b01aa45758377d984ff82382141b12110fd1d0 100644 (file)
@@ -39,6 +39,7 @@ set(BUILT_SOURCES
 )
 
 set (UNBUILT_SOURCES
+    daq.txt
     differences.txt
     errors.txt
     enviro.txt
index 07a2000698d5d7690075357196f7c5d69831eec7..5d98af362d933ec719ec95e7829975583719f8ea 100644 (file)
@@ -28,6 +28,7 @@ snort2lua_cmds.txt
 unbuilt_sources = \
 snort_manual.txt \
 config_changes.txt \
+daq.txt \
 differences.txt \
 enviro.txt \
 errors.txt \
index b5c529227e765b63e6d93289fcb037cd209bdaf1..641773862f2f4d236722209b16d28e4edc104caf 100644 (file)
@@ -136,6 +136,7 @@ change -> rule_state: 'disabled' ==> 'enable'
 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'
@@ -264,6 +265,15 @@ deleted -> rule_state: 'action'
 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'
diff --git a/doc/daq.txt b/doc/daq.txt
new file mode 100644 (file)
index 0000000..7e40f81
--- /dev/null
@@ -0,0 +1,569 @@
+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.
+
index d18d00a664abb5f6ef60c0db2ed07034228ea164..065c9a7c6c263f82f8eb93ee4ab6e0eb3f696cd7 100644 (file)
@@ -80,6 +80,10 @@ All output of events and packets is done by Loggers.
 
 include::logger.txt[]
 
+== DAQ Modules
+
+include::daq.txt[]
+
 == Snort++ vs Snort
 
 include::differences.txt[]
index aee23fcd9c2f5440aef32c968251c0b8194a3d4d..332601c7f3b5208db38bfce815f1012017ee4e03 100644 (file)
@@ -32,7 +32,11 @@ AC_PROG_LIBTOOL
 # 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
 
@@ -69,10 +73,9 @@ AC_DEFUN([CC_VISIBILITY],
 ])
 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}"
@@ -85,6 +88,7 @@ AC_CONFIG_FILES([ \
     Makefile \
     src/Makefile \
     src/codecs/Makefile \
+    src/daqs/Makefile \
     src/inspectors/Makefile \
     src/ips_options/Makefile \
     src/loggers/Makefile \
index bd6aa0b02ab8ee0a5d417e762f21467f10d46a0d..8552dcfafd9aa9961876b241146ac3000468d5b5 100644 (file)
@@ -79,6 +79,7 @@ endif (BUILD_EXTRA_PLUGINS)
 
 
 add_subdirectory (codecs)
+add_subdirectory (daqs)
 add_subdirectory (inspectors)
 add_subdirectory (ips_options)
 add_subdirectory (loggers)
index 8481a3813d18ab8eb2a6e19f05ffb1b06c474a51..9f5851af36cb4f2aff2bb7ecd5261c5200e4d19c 100644 (file)
@@ -2,6 +2,7 @@ AUTOMAKE_OPTIONS=foreign
 
 SUBDIRS = \
 codecs \
+daqs \
 inspectors \
 ips_options \
 loggers \
index d01f92d1eb237f7d69d3d2cf8afc0d7eec640641..6d921ea7d1478fe3cb89af7d0168f593c4c0ff8b 100644 (file)
@@ -1,16 +1,5 @@
 
 
-###################################
-#######  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)
index f9b3fe6bc77984bdefc0521bb4d86448d3812b24..82f7a475f04f29d52a0b15876d06747f12843948 100644 (file)
@@ -1,15 +1,21 @@
 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@
+
diff --git a/extra/src/codecs/daq204.diff b/extra/src/codecs/daq204.diff
new file mode 100644 (file)
index 0000000..9456273
--- /dev/null
@@ -0,0 +1,738 @@
+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
diff --git a/extra/src/codecs/socket.cc b/extra/src/codecs/socket.cc
new file mode 100644 (file)
index 0000000..b12c0b4
--- /dev/null
@@ -0,0 +1,152 @@
+//--------------------------------------------------------------------------
+// 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
+};
+
diff --git a/extra/src/daqs/CMakeLists.txt b/extra/src/daqs/CMakeLists.txt
new file mode 100644 (file)
index 0000000..4dc9e7c
--- /dev/null
@@ -0,0 +1,6 @@
+
+
+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)
+
diff --git a/extra/src/daqs/Makefile.am b/extra/src/daqs/Makefile.am
new file mode 100644 (file)
index 0000000..241cb3a
--- /dev/null
@@ -0,0 +1,21 @@
+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@
+
diff --git a/extra/src/daqs/daq_file.c b/extra/src/daqs/daq_file.c
new file mode 100644 (file)
index 0000000..1b5730f
--- /dev/null
@@ -0,0 +1,401 @@
+/*--------------------------------------------------------------------------
+// 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,
+};
+
diff --git a/extra/src/daqs/daq_socket.c b/extra/src/daqs/daq_socket.c
new file mode 100644 (file)
index 0000000..e98f84d
--- /dev/null
@@ -0,0 +1,598 @@
+/*--------------------------------------------------------------------------
+// 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,
+};
+
diff --git a/extra/src/daqs/daq_socket.h b/extra/src/daqs/daq_socket.h
new file mode 100644 (file)
index 0000000..5f7fc6e
--- /dev/null
@@ -0,0 +1,46 @@
+/*--------------------------------------------------------------------------
+// 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
+
diff --git a/extra/src/daqs/daq_user.c b/extra/src/daqs/daq_user.c
new file mode 100644 (file)
index 0000000..4203a2e
--- /dev/null
@@ -0,0 +1,608 @@
+/*--------------------------------------------------------------------------
+// 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,
+};
+
index e76537eb90034576639bcbb5ada9a05188c574e9..49f4986308efa307e1ee23578de197249fb8c837 100644 (file)
@@ -54,9 +54,7 @@ static THREAD_LOCAL TextLog* tlog = nullptr;
 
 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()
index bbe03776585043b0ded9910b37297ae3757a489a..a9592c9a9f86050830ad6c284d2d37d27bb74076 100644 (file)
@@ -1,5 +1,6 @@
 
 add_example_library(alert_ex loggers alert_ex.cc)
+add_example_library(log_user loggers log_user.cc)
 
 install (
     FILES alert.lua
index b4c2929a1643fb8951b426b562486c10dfd49071..e5680f2f76f5aaed24c6364a32598ca8fa30f2e8 100644 (file)
@@ -1,11 +1,17 @@
 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@
diff --git a/extra/src/loggers/log_user.cc b/extra/src/loggers/log_user.cc
new file mode 100644 (file)
index 0000000..5c362c7
--- /dev/null
@@ -0,0 +1,254 @@
+//--------------------------------------------------------------------------
+// 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
+};
+
index a68135fa50ebd6c73c563ac3a91e7d0798b0f9f1..ad769317f772051003f30e2e7cf246ec58fbbb64 100644 (file)
@@ -13,5 +13,5 @@ Description: Snort dynamic plugins/detection/rules
 URL: www.snort.org
 Version: @VERSION@
 Libs: -L${libdir} -lcurl @LDFLAGS@ @LIBS@
-Cflags: -I${includedir} @CFLAGS@ @CPPFLAGS@
+Cflags: @CFLAGS@ @CPPFLAGS@
 
index d5db97dfd9da395655831b16414fcb68c1c2dc14..7a869e09a6b8474b3c38890a163ce64712415417 100644 (file)
@@ -101,6 +101,8 @@ target_link_libraries( snort
     stream_icmp
     stream_tcp
     stream_udp
+    stream_user
+    stream_file
     http_inspect
     flow
     parser
index eed74a74410c4c98b6ded858410375c7d44fb102..f2ac1688372a24fed360877faad9237f5b964632 100644 (file)
@@ -48,12 +48,14 @@ network_inspectors/perf_monitor/libperf_monitor.a \
 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 \
index c93dcb184bbf9247e5cc6fb0eedd4a63cbdb4ae8..dcc39356e67f1f7a0fb62012d25d5b1ef98c0ac7 100644 (file)
@@ -1,5 +1,6 @@
 //--------------------------------------------------------------------------
 // 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
index 36d1a77b23f4689719e695ce6a363082e0ca050a..656ca8d6a1d18dd66ca80c5ece2bfe2780d1b75a 100644 (file)
@@ -150,7 +150,7 @@ ReplaceAction::ReplaceAction(ReplaceModule*) :
 
 void ReplaceAction::exec(Packet* p)
 {
-    if ( PacketIsRebuilt(p) )
+    if ( p->is_rebuilt() )
         return;
 
     Replace_ModifyPacket(p);
index 3249d411ad8452923b94f630181fd069122d4f3a..3ec04eb2944d57a1f0b182312820158d84bf5473 100644 (file)
@@ -1,6 +1,6 @@
 //--------------------------------------------------------------------------
-// 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
index 25b54fe5f34ab35bd7078e988d566949027d5f7f..3e5b6b2bdbdebe5e24365ee4a4d7ff157cb80640 100644 (file)
@@ -1,6 +1,6 @@
 //--------------------------------------------------------------------------
-// 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
index ce4008bfc27a8ac4bad53d5a41d7a67772f01ec3..c5401d46a72ce2a30d04392790024ad2c1781091 100644 (file)
@@ -1,6 +1,6 @@
 //--------------------------------------------------------------------------
-// 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
index a6b86e464971663406f4dced69119eabc2d20465..9b623053e70e53e824a21a1552adcded663141c6 100644 (file)
@@ -1,6 +1,6 @@
 //--------------------------------------------------------------------------
-// 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
index 24a4d166699a97a1917ac9e622ca0bb3a4d52be4..ceb90f276b2acb24bc9f1df46688817863633231 100644 (file)
@@ -1,6 +1,6 @@
 //--------------------------------------------------------------------------
-// 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
index 48d96677005f1efff2c3a652952aa7251dc03fe4..c26221990224e1fb882d6bd0603ace09f9eabd6b 100644 (file)
@@ -1,6 +1,6 @@
 //--------------------------------------------------------------------------
-// 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
index 6c065c99d152bea8140d438f84b538f015234605..c6440529ba26796321fecf289d1a00aaa203d693 100644 (file)
@@ -1,6 +1,6 @@
 //--------------------------------------------------------------------------
-// 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
index 801368a97ab8e00f2ce9935308adff04c4f948c0..68744478cda15d09de6c3404e169c2f170760caa 100644 (file)
@@ -1,6 +1,6 @@
 //--------------------------------------------------------------------------
-// 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
index 849d142749a590c456fc765e132e8a6e52299f6d..9e3727b50088f1562e8d27ac191ddbae4d7e28cf 100644 (file)
@@ -1,6 +1,6 @@
 //--------------------------------------------------------------------------
-// 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
index dd3c7650b34832017e34258246f802ab5dbfd458..41587b31e907b8bcaa5c280981389587c74fa1ea 100644 (file)
@@ -1,6 +1,6 @@
 //--------------------------------------------------------------------------
-// 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
index 64911d89a8c00a31b0f29aac5d6eae2d363724de..091e0284e7e3c0d7d602f37a38064bce4da01e67 100644 (file)
@@ -1,6 +1,6 @@
 //--------------------------------------------------------------------------
-// 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
index b257a1a385d85e1bd2ca6b1f39e60c218191361f..49bc7daba6eed7eb71e7e3a693ae82b2fa6f87c7 100644 (file)
@@ -1,6 +1,6 @@
 //--------------------------------------------------------------------------
-// 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
index dc5e01df4f818a666f5d4e57f8f3d00057951c43..4ae635661378d4bcd9ae6d63465b42cc3007e10a 100644 (file)
@@ -1,6 +1,6 @@
 //--------------------------------------------------------------------------
-// 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
index 306534e59dbe8272431122f4e03ab0056ad097b8..956e424a604370ab9732e1ee07c9f95f890f81d8 100644 (file)
@@ -1,6 +1,6 @@
 //--------------------------------------------------------------------------
-// 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
index 6425e338d5d97e2f7bf553fd87d99ff2ec586fd5..5488e95e30d8fc7b2ba1ed5d0e0de8f4f352f9b5 100644 (file)
@@ -10,10 +10,10 @@ if(STATIC_CODECS)
 
 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)
 
index a3fe55a7c040b984cafef2a4d6d0e54c0b700994..d5a2f4d9eccba32fa49f4ad35e9ee714de0446c2 100644 (file)
@@ -14,36 +14,34 @@ cd_teredo.cc
 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@
+
index e836d105ea532b55ebc233dfc5f888a2b2009743..e966b5418f2301d415a904e605591ff13fa9a82b 100644 (file)
@@ -1,6 +1,6 @@
 //--------------------------------------------------------------------------
-// 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
index 04be25a4b831adcb131258a8d2b6e51bdbdf510b..13f49e74a604822f36f345cb8a4e8ca65517ff33 100644 (file)
@@ -1,6 +1,6 @@
 //--------------------------------------------------------------------------
-// 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
index 247d0a9dca76aae3bc7a61cede406e81c39326d6..e3106a717d9e8eb67ace07211fcf1b250f614568 100644 (file)
@@ -1,6 +1,6 @@
 //--------------------------------------------------------------------------
-// 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
index 3d133561503114c823ea25140ad999bc3b999e39..31f5b99858df0577a189fffc6512f70dc2378eb5 100644 (file)
@@ -1,6 +1,6 @@
 //--------------------------------------------------------------------------
-// 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
index 387bbbb3bb779022ac14ecd90acc16b6447e360e..ea979af9171f3b9c912f78026da3214e35bae467 100644 (file)
@@ -1,7 +1,7 @@
 //--------------------------------------------------------------------------
-// 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
@@ -338,6 +338,8 @@ bool Detect(Packet* p)
     case PktType::TCP:
     case PktType::UDP:
     case PktType::ICMP:
+    case PktType::USER:
+    case PktType::FILE:
     {
         PROFILE_VARS;
 
index afa668c7d42d279215ea18980c1d948b51dc09a4..3058fb0fe6e1239550bffe841b1a7093cc81f5b5 100644 (file)
@@ -1515,17 +1515,25 @@ int fpEvalPacket(Packet* p)
         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
index f8889b2ed79093bb25a11b3e311be128797d1562..3147a6845895dccaf2e1b9e3aa982b423aa35bbc 100644 (file)
@@ -1,7 +1,7 @@
 //--------------------------------------------------------------------------
-// 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
@@ -470,7 +470,7 @@ int CheckTagList(Packet* p, Event* event, void** log_list)
         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;
index e664efb3549018297ce21e61cc95502e709656fb..8d9de1f7351b96532b957aa40ea55c7a34439a31 100644 (file)
@@ -15,3 +15,6 @@ add_library ( file_api STATIC
     file_mime_config.cc 
     file_mime_config.h
 )
+
+target_link_libraries(file_api file)
+
index 65186b1169a611c01f86b0b84f0f1c75b8eff3b1..267d9a18c4ffbb0ee1e28d699108f455a3000422 100644 (file)
@@ -172,9 +172,11 @@ typedef File_Verdict (* File_signature_done_func) (void* p, Flow* flow, uint8_t*
     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);
index ac9852f9b7c1673f534d1ddcefc1b86f4207a880..7531f3d71fc7c17ad96a1305663d878bb74e0c1b 100644 (file)
@@ -35,6 +35,7 @@
 
 #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;
 
@@ -87,8 +94,6 @@ static uint32_t str_to_hash(uint8_t* str, int length);
 
 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);
@@ -274,8 +279,8 @@ static FileContext* get_file_context(void* p, FilePosition position, bool upload
     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];
@@ -386,8 +391,6 @@ static void DumpHex(FILE* fp, const uint8_t* data, unsigned len)
     }
 }
 
-#endif
-
 static inline void updateFileSize(FileContext* context, int data_size, FilePosition position)
 {
     context->processed_bytes += data_size;
@@ -606,13 +609,12 @@ static int file_process(void* p, uint8_t* file_data, int 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))
@@ -698,16 +700,9 @@ static int file_process(void* p, uint8_t* file_data, int data_size,
     {
         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);
@@ -718,14 +713,10 @@ static void set_file_name(Flow* flow, uint8_t* file_name, uint32_t name_size)
 {
     /* 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,
@@ -852,9 +843,9 @@ static FilePosition get_file_position(void* pkt)
     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;
@@ -934,25 +925,34 @@ static uint32_t str_to_hash(uint8_t* str, int length)
     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] ))
         {
@@ -966,15 +966,25 @@ static void print_file_stats(int exiting)
     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] ))
         {
@@ -988,9 +998,10 @@ static void print_file_stats(int exiting)
     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];
@@ -1063,6 +1074,7 @@ static void print_file_stats(int exiting)
         }
     }
     LogMessage("   %12s:           " FMTu64("-10") " \n", "Total",verdicts_total);
+#endif
 
     {
         LogMessage("\nFiles processed by protocol IDs:\n");
@@ -1084,9 +1096,6 @@ static void print_file_stats(int exiting)
             }
         }
     }
-
-    LogMessage("\nTotal files processed:     " FMTu64("-10") " \n", file_stats.files_total);
+    //LogMessage("\nTotal files processed:     " FMTu64("-10") " \n", file_stats.files_total);
 }
 
-#endif
-
index 7f19c79bc57029814f6073d16aba5fa35ce679af..2cbe9f47de9f7292bf9f11c55f12568390cf517f 100644 (file)
@@ -32,7 +32,8 @@
 #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
 
index 6e4fe4f89d16ab1e01d65f6691b85eb546a63061..99ffe02d064a3e2c5652ee6c6efb8717152e7ab7 100644 (file)
@@ -51,9 +51,11 @@ public:
     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;
index edd11e7f09dd877443f3e34c613adde01421b6c3..ee0b73d758a56d74548a62690a0d1d804a9f1701 100644 (file)
@@ -291,7 +291,7 @@ void FileIdenfifier::update_trie(IdentifierNode* start, IdentifierNode* append)
         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;
         }
index 963ae163ada4f9aa1a82928c7fc554c092efb81a..331fd8dfde2eab9c030dcdecccfb8c19508e486f 100644 (file)
@@ -76,7 +76,8 @@ static inline int get_data_size_from_depth_limit(FileContext* context, FileProce
 }
 
 /*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;
 
@@ -119,8 +120,8 @@ void file_type_id(FileContext* context, uint8_t* file_data, int data_size, FileP
     }
 }
 
-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;
@@ -251,7 +252,6 @@ const char* file_info_from_ID(void* conf, uint32_t id)
     return NULL;
 }
 
-#if defined(DEBUG_MSGS) || defined (REG_TEST)
 /*
  * Print a 32-byte hash value.
  */
@@ -271,5 +271,3 @@ void file_sha256_print(unsigned char* hash)
         hash[28], hash[29], hash[30], hash[31]);
 }
 
-#endif
-
index 057d1b0dbf6bdf3263388933cde10160174385ff..d84c4e103344d310f088aae8a7761a4ad354fbcb 100644 (file)
@@ -106,8 +106,7 @@ extern int64_t file_type_depth;
 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
 
index f8e443947feeca54f297d5c34a547b87ad6f7b95..8bf44aa814ff9696bdd8188ae016fcdc884e7938 100644 (file)
@@ -131,7 +131,7 @@ int RateFilter_Test(
     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();
index 6dce6d931e76ec86adcdf29332d7ee0be4a94e1b..d3d4bb5f1c60d01f24738b6d48bc27457acf2b04 100644 (file)
@@ -123,18 +123,18 @@ struct ExpectKey
     sfip_t ip2;
     uint16_t port1;
     uint16_t port2;
-    uint32_t protocol;
+    PktType protocol;
 
     bool set(
-        const sfip_tcliIP, uint16_t cliPort,
-        const sfip_tsrvIP, 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_tcliIP, uint16_t cliPort,
-    const sfip_tsrvIP, 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);
@@ -155,7 +155,7 @@ inline bool ExpectKey::set(
         port2 = cliPort;
         reverse = true;
     }
-    protocol = static_cast<uint32_t>(proto);
+    protocol = proto;
     return reverse;
 }
 
@@ -343,9 +343,9 @@ ExpectCache::~ExpectCache ()
  * session expiry in seconds.
  */
 int ExpectCache::add_flow(
-    const sfip_tcliIP, uint16_t cliPort,
-    const sfip_tsrvIP, 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);
@@ -391,7 +391,7 @@ bool ExpectCache::is_expected(Packet* p)
     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;
index b3ac5444859a8f4e799745c82c864331c18f1981..c9c8975d3be709f462ca23004420d943b4f28582 100644 (file)
@@ -32,10 +32,9 @@ public:
     ~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*);
index 7ff5c55065b2e9c776bb90f5ade1894938199be2..40ce2a95390edbe670cb9912a056688091716291 100644 (file)
@@ -378,7 +378,7 @@ void Flow::set_ttl(Packet* p, bool client)
      * 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()?
index 15dde223fb2b59f15020fd4e56889b01a0ac3ea5..c32c01cbe8c3d689a7fe11d532505bf02cfe7dbd 100644 (file)
@@ -35,6 +35,7 @@
 #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 */
 
@@ -62,6 +63,7 @@
 #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
@@ -125,13 +127,6 @@ struct LwState
     char ignore_direction;
 };
 
-enum Stream_Event
-{
-    SE_REXMIT,
-    SE_EOF,
-    SE_MAX
-};
-
 // this struct is organized by member size for compactness
 class Flow
 {
@@ -170,12 +165,18 @@ public:
 
     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; }
 
@@ -277,11 +278,10 @@ public:  // FIXIT-M privatize if possible
     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
index 411a0628e9e888ddc04079008f04959e967c8561..67a515d630a73e37f75aeda1ad3d6738bda1a22f 100644 (file)
@@ -47,39 +47,49 @@ FlowControl::FlowControl()
     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);
 
@@ -89,42 +99,50 @@ uint32_t FlowControl::max_flows(uint8_t 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();
 }
 
@@ -132,21 +150,23 @@ void FlowControl::clear_counts()
 // 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);
@@ -156,7 +176,7 @@ Flow* FlowControl::find_flow(const FlowKey* 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;
@@ -168,7 +188,7 @@ Flow* FlowControl::new_flow(const FlowKey* key)
 // 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;
@@ -181,13 +201,13 @@ void FlowControl::delete_flow(const FlowKey* key)
 
 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);
 
@@ -195,7 +215,7 @@ void FlowControl::purge_flows(uint8_t 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);
 
@@ -214,17 +234,23 @@ void FlowControl::timeout_flows(uint32_t flowCount, time_t cur_time)
 {
     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();
 }
@@ -239,7 +265,8 @@ void FlowControl::set_key(FlowKey* key, Packet* p)
     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();
@@ -259,18 +286,18 @@ void FlowControl::set_key(FlowKey* key, Packet* p)
 
     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);
     }
 }
 
@@ -281,6 +308,13 @@ static bool is_bidirectional(const Flow* flow)
 }
 
 // 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() )
@@ -326,17 +360,35 @@ static void init_roles_udp(Packet* p, Flow* flow)
     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;
@@ -345,9 +397,9 @@ static void init_roles(Packet* p, Flow* flow)
         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:
@@ -418,6 +470,107 @@ unsigned FlowControl::process(Flow* flow, Packet* p)
     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
 //-------------------------------------------------------------------------
@@ -517,114 +670,106 @@ void FlowControl::process_udp(Packet* p)
 }
 
 //-------------------------------------------------------------------------
-// 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 )
@@ -651,9 +796,9 @@ char FlowControl::expected_flow(Flow* flow, Packet* p)
 }
 
 int FlowControl::add_expected(
-    const sfip_tsrcIP, uint16_t srcPort,
-    const sfip_tdstIP, 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(
@@ -661,9 +806,9 @@ int FlowControl::add_expected(
 }
 
 int FlowControl::add_expected(
-    const sfip_tsrcIP, uint16_t srcPort,
-    const sfip_tdstIP, 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);
index 41c731e3b919d29c811d6a06f6846d6965d080f5..5981979764a983b61721aa448da99c34660aeed8 100644 (file)
@@ -42,62 +42,72 @@ public:
     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_tsrcIP, uint16_t srcPort,
-        const sfip_tdstIP, 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_tsrcIP, uint16_t srcPort,
-        const sfip_tdstIP, 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;
 };
index dc5f00f345e3c5e46ea82281402703e5482f6afb..42ef0fe8d921b6c9e8473b63029a65231880138e 100644 (file)
 //-------------------------------------------------------------------------
 
 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;
@@ -97,9 +98,10 @@ inline void FlowKey::init4(
 }
 
 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;
@@ -168,10 +170,10 @@ inline void FlowKey::init6(
         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;
 }
@@ -199,10 +201,10 @@ void FlowKey::init_mpls(uint32_t mplsId)
 }
 
 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
@@ -210,21 +212,26 @@ void FlowKey::init(
      * 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
@@ -235,17 +242,16 @@ void FlowKey::init(
     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);
 }
 
index e4585151f9b44e8b959063b0c0e9e6f98a00822f..77c4a2208a5bbef181b360e56049b714e895c151 100644 (file)
 
 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);
@@ -58,14 +59,16 @@ struct FlowKey
 
 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
index 6910507b5019be250c5d378e8f239a61db7ec62e..add6ba69fb63c6590010e2b819b6c7c2cb912a7f 100644 (file)
@@ -21,6 +21,7 @@
 #define SESSION_H
 
 #include "sfip/sfip_t.h"
+#include "stream/stream_api.h"
 
 struct Packet;
 class Flow;
@@ -41,6 +42,30 @@ public:
     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; }
 
index d248688183ded31796e6f247482d364f6ac57d95..283e6b5b4ba179c54b4494dbc8dc249a30f11f7d 100644 (file)
@@ -35,6 +35,7 @@
 #include "framework/decode_data.h"
 
 struct TextLog;
+struct _daq_pkthdr;
 struct Packet;
 struct Layer;
 enum CodecSid : uint32_t;
@@ -66,40 +67,50 @@ constexpr uint8_t MAX_TTL = 255;
 
 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
 {
index ee1788f04e4229f976a738221a43e7d913165934..e7c1175ddfe1e08e929eff6a5d6b9d7e656ec8c7 100644 (file)
@@ -43,34 +43,41 @@ struct ICMPHdr;
 /* 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!!
@@ -99,18 +106,17 @@ enum DecodeFlags : std::uint16_t
 
 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;
 
@@ -130,5 +136,5 @@ struct DecodeData
     { return type; }
 };
 
-#endif /* FRAMEWORK_DECODE_DATA_H */
+#endif
 
index 3e93e8c06537319934c191bb04f6458574f43599..8eacc1b045a4c8bd7cc2265059bf1567291c7a78 100644 (file)
@@ -201,9 +201,7 @@ int FlowCheckOption::eval(Cursor&, Packet* p)
     /* ...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;
index b4eddcc1a601dc2f4c79947f4f0ce2a092fec794..d96533c63e72741dd799fbe5e384fd095a5ca594 100644 (file)
@@ -148,7 +148,7 @@ int FragBitsOption::eval(Cursor&, Packet* p)
     int rval = DETECTION_OPTION_NO_MATCH;
     PROFILE_VARS;
 
-    if (!p->ptrs.ip_api.is_valid())
+    if(!p->ptrs.ip_api.is_ip())
     {
         return rval;
     }
index bff372b56c2f730979c362bd6ddcecd797d893b8..ae54161b8fe1f7f79462f5498351292bce60dd9f 100644 (file)
@@ -1,8 +1,8 @@
 //--------------------------------------------------------------------------
-// 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
index 3261ff3de65d6941f62bb57bfe41fbec3ae448e5..3aeab276c9e9e06ca80e00433db59ecc3d41114c 100644 (file)
@@ -162,7 +162,7 @@ int ReplaceOption::eval(Cursor& c, Packet* p)
     PROFILE_VARS;
     MODULE_PROFILE_START(replacePerfStats);
 
-    if ( PacketWasCooked(p) )
+    if ( p->is_cooked() )
         return false;
 
     if ( !c.is("pkt_data") )
index 269a493abd6189fc731c22c6b570a6b4070b7b56..3adeac41da2359a17c8727d113f2504cce1de94e 100644 (file)
@@ -87,7 +87,7 @@ int IpTosOption::eval(Cursor&, Packet* p)
     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);
index 9e4e12dfae6a7de7c0425ba39854421e451d7817..ea3a8ba7547e89c5fcfa5d6de06ae5fba00fb2ec 100644 (file)
@@ -86,7 +86,7 @@ int TtlOption::eval(Cursor&, Packet* p)
     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);
index ddd99343435e7d9848a80cb817f17957d0a34902..2fe9934426988646ee507f025bdf146ba1fd3a63 100644 (file)
@@ -155,7 +155,7 @@ void LogIPPkt(Packet* p)
 
 void snort_print(Packet* p)
 {
-    if (p->ptrs.ip_api.is_valid())
+    if (p->ptrs.ip_api.is_ip())
     {
         LogIPPkt(text_log, p);
     }
index 04102462b33d369a8b38b18a9d89f58ebea68069..0f8ff649c87ec15db64963c3d37a9bbcb9921e68 100644 (file)
@@ -572,9 +572,6 @@ void LogIpOptions(TextLog* log, const IP4Hdr* ip4h, const Packet* const 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";
@@ -623,7 +620,7 @@ void LogIpAddrs(TextLog* log, Packet* p)
  */
 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;
@@ -952,7 +949,7 @@ void LogTCPHeader(TextLog* log, Packet* p)
     /* 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())
     {
@@ -1709,7 +1706,7 @@ static void LogPacketType(TextLog* log, Packet* p)
 {
     TextLog_NewLine(log);
 
-    if ( !p->dsize || !PacketWasCooked(p) )
+    if ( !p->dsize || !p->is_cooked() )
         return;
 
     switch ( p->pseudo_type )
@@ -1854,7 +1851,11 @@ void LogIPPkt(TextLog* log, Packet* p)
             break;
         }
     }
+    LogPayload(log, p);
+}
 
+void LogPayload(TextLog* log, Packet* p)
+{
     if ((p->dsize > 0) && obApi->payloadObfuscationRequired(p)
         && (LogObfuscatedData(log, p) == 0))
     {
index a484b889e509c8ca0c0bbd4bd87a098de8367b2d..0da2db3e5fb4d475b913818652b365cf79039bec 100644 (file)
@@ -55,6 +55,7 @@ void LogPriorityData(TextLog*, const Event*, bool doNewLine);
 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*);
index 108fa91106e6ba5f1f1ce9b526f100871392a90e..2162c28835510f7e4a727062dccdb3314d7a28b4 100644 (file)
@@ -195,7 +195,7 @@ static void LogReassembly(const Packet* p)
 {
     /* 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 )
@@ -222,7 +222,7 @@ static void LogReassembly(const Packet* p)
         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;
     }
 }
@@ -230,7 +230,6 @@ static void LogReassembly(const Packet* p)
 #endif
 
 #ifndef REG_TEST
-
 static const char* get_pkt_type(Packet* p)
 {
     switch ( p->ptrs.get_pkt_type() )
@@ -243,7 +242,6 @@ static const char* get_pkt_type(Packet* p)
     }
     return "error";
 }
-
 #endif
 
 void FastLogger::alert(Packet* p, const char* msg, Event* event)
@@ -298,7 +296,6 @@ 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
@@ -317,6 +314,8 @@ void FastLogger::alert(Packet* p, const char* msg, Event* event)
 #endif
         if (p->has_ip())
             LogIPPkt(fast_log, p);
+        else
+            LogPayload(fast_log, p);
 
 #if 0
         // FIXIT-L -J LogArpHeader unimplemented
index 24a07abfd4f3ccf34d7ea15fc37594ad26159ecc..8fe0582876e58c389b63592737964deaef6393c1 100644 (file)
@@ -293,7 +293,7 @@ struct SnortActionRequest
 
 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
index 2a927236bab2aa97d6f3ac8081c2a92265889f7b..a71d326cb73dab9eb338f33aa7db857a18f26e96 100644 (file)
@@ -239,7 +239,9 @@ static void AlertSyslog(
             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)
         {
index 7f2ab1208fbbd0895a6dbf6074f2a2dd2d343065..d4cdcc89faf3cf23f7f4cb835376b2edefe927de 100644 (file)
@@ -272,7 +272,7 @@ static void _AlertIP4_v2(Packet* p, const char*, Unified2Config* config, Event*
             alertdata.ip_source = iph->get_src();
             alertdata.ip_destination = iph->get_dst();
 
-            if (IsPortscanPacket(p))
+            if (p->is_portscan())
             {
                 alertdata.protocol = p->ps_proto;
             }
@@ -286,7 +286,7 @@ static void _AlertIP4_v2(Packet* p, const char*, Unified2Config* config, Event*
                     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);
@@ -356,7 +356,7 @@ static void _AlertIP6_v2(Packet* p, const char*, Unified2Config* config, Event*
     {
         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;
 
@@ -366,7 +366,7 @@ static void _AlertIP6_v2(Packet* p, const char*, Unified2Config* config, Event*
             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;
             }
@@ -380,7 +380,7 @@ static void _AlertIP6_v2(Packet* p, const char*, Unified2Config* config, Event*
                     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);
index 4d0160b9dc9d12b2ae72ad4c89e8dd0a610f6ade..92547e87c9110b89e9ced350b9659a4d9717127c 100644 (file)
@@ -1279,6 +1279,7 @@ bool ProcessModule::end(const char* fqn, int idx, SnortConfig* sc)
 //-------------------------------------------------------------------------
 // file_id module
 //-------------------------------------------------------------------------
+
 static const Parameter file_magic_params[] =
 {
     { "content", Parameter::PT_STRING, nullptr, nullptr,
@@ -1333,7 +1334,6 @@ static const Parameter file_id_params[] =
     { "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" },
 
@@ -1342,10 +1342,19 @@ static const Parameter file_id_params[] =
 
     { "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 }
 };
 
@@ -1384,16 +1393,28 @@ bool FileIdModule::set(const char*, Value& v, SnortConfig* sc)
     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;
 
@@ -1466,7 +1487,7 @@ bool FileIdModule::end(const char* fqn, int idx, SnortConfig* sc)
     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") )
index 9f55c4a513380aebd09cc1d67dd14ed14be09654..46eb97677f0b9db5b02df1d39f2655f588e2cc58 100644 (file)
@@ -96,6 +96,7 @@ enum OutputFlag
 
     OUTPUT_FLAG__NO_ALERT          = 0x00001000,      /* -A none */
     OUTPUT_FLAG__NO_LOG            = 0x00002000,      /* -K none */
+    OUTPUT_FLAG__ALERTS            = 0x00004000,      /* -A != none */
 };
 
 enum LoggingFlag
index 3ccee6f17c92f65502162d90ac055fa5c8393d22..2069547a0f9d98b225c62dafb65c86d12c5b5961 100644 (file)
@@ -149,12 +149,12 @@ static const Parameter s_params[] =
       "<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" },
 
@@ -544,12 +544,12 @@ bool SnortModule::set(const char*, Value& v, SnortConfig* sc)
         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());
 
index 9c9512182de42b2e85e12867db142c33a72a1c85..f745a75575df7932f5869633c1f2d4a4e88add03 100644 (file)
@@ -226,8 +226,8 @@ void CodecManager::thread_init(SnortConfig* sc)
         }
     }
 
-    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 )
@@ -239,7 +239,7 @@ void CodecManager::thread_init(SnortConfig* sc)
     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
index 52970fe576d566637d1d8493ab74bffd24d0ff48..b637d81d48f318ebf3e9d1b5171f6c026fce1164 100644 (file)
@@ -113,7 +113,25 @@ static Output* get_out(const char* key)
         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)
@@ -178,15 +196,20 @@ void EventManager::instantiate(
     // 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);
index 476de737d56fcf502cfc5a08f09123690ced6f14..3ac025d53b778eaafa4187f1a0524155d1bf030d 100644 (file)
@@ -613,6 +613,9 @@ static void instantiate_binder(SnortConfig* sc, FrameworkPolicy* fp)
     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;
@@ -707,11 +710,12 @@ static inline void execute(
         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;
@@ -722,7 +726,7 @@ void InspectorManager::bumble(Packet* p)
 
     flow->clear_clouseau();
 
-    if ( !flow->gadget || flow->protocol != PktType::TCP )
+    if ( !flow->gadget || !flow->is_stream() )
         return;
 
     if ( flow->session )
@@ -743,7 +747,7 @@ void InspectorManager::full_inspection(FrameworkPolicy* fp, Packet* p)
         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;
@@ -756,10 +760,10 @@ void InspectorManager::execute(Packet* p)
     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;
index b8d00bdd8900a55dc24a8f9140712aeeea95eae1..bb14af188f498fad88b93865d8f98323502c4032 100644 (file)
@@ -68,7 +68,7 @@ static const Parameter binder_when_params[] =
     { "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,
@@ -151,8 +151,9 @@ bool BinderModule::set(const char* fqn, Value& v, SnortConfig*)
     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()];
     }
index 677bfbfec4a291c8c31758679907f72c455ba3d6..a0159363eccb2416ef2b449eedb91b23ccf254d2 100644 (file)
@@ -25,13 +25,13 @@ using namespace std;
 #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"
@@ -50,6 +50,8 @@ THREAD_LOCAL ProfileStats bindPerfStats;
 #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
@@ -331,6 +333,14 @@ void Stuff::apply_session(Flow* flow, const HostAttributeEntry* host)
         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);
     }
@@ -437,7 +447,7 @@ int Binder::exec(int, void* pv)
     if ( ins )
         flow->set_gadget(ins);
 
-    if ( flow->protocol != PktType::TCP )
+    if ( !flow->is_stream() )
         return 0;
 
     if ( ins )
index 1fd098b69f2d3275a694e22d64567bf46318317f..7d8a1366fdea5060eb87c9930e9a6f35d151b4cf 100644 (file)
 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
@@ -45,16 +38,9 @@ const BaseApi* network_inspectors[] =
     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
index bb91dfc7b3698e5dc18e7220844aab78b5f31ad8..3154c861b43bd650fd47df7abae4fb9976fc3ed9 100644 (file)
@@ -247,7 +247,7 @@ void Normalizer::eval(Packet* p)
     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);
index 514bb8395678a3372d912035164f5d73ac1543f2..0fcfabf1be1b54477d0007f5beffb2b325b1d157 100644 (file)
@@ -465,7 +465,7 @@ void sfPerformanceStats(SFPERF* sfPerf, Packet* p)
     // 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;
 
@@ -571,7 +571,7 @@ void InitPerfStats(SFPERF* sfPerf)
 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);
index 2b015ab7a73a22edb1413bcbdaa5064d9c5e9e4e..26bf6c1d0571d9ef9a72cf73098d17a291610f06 100644 (file)
@@ -186,7 +186,7 @@ static int LogPortscanAlert(Packet* p, uint32_t event_id,
     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 */
@@ -382,7 +382,7 @@ static int MakePortscanPkt(PS_PKT* ps_pkt, PS_PROTO* proto, int proto_type,
     }
     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);
     }
 
@@ -916,7 +916,7 @@ void PortScan::eval(Packet* p)
     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;
@@ -1029,7 +1029,7 @@ static const InspectApi sp_api =
         mod_dtor
     },
     IT_PROBE,
-    (uint16_t)PktType::ANY_IP,  // FIXIT-L dynamic assign
+    (uint16_t)PktType::IP,
     nullptr, // buffers
     nullptr, // service
     nullptr, // pinit
index 5e682ea6a0d0536db3a2d13b2e5d213bba9f0528..83e34cc7b6eeed4311e8e2012fb6876054200832 100644 (file)
@@ -335,7 +335,7 @@ int PortScan::ps_filter_ignore(PS_PKT* ps_pkt)
 
     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)
@@ -594,10 +594,10 @@ int PortScan::ps_get_proto(PS_PKT* ps_pkt, int* proto)
 
     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;
@@ -1009,7 +1009,7 @@ int PortScan::ps_tracker_update_ip(PS_PKT* ps_pkt, PS_TRACKER* scanner,
 
     p = (Packet*)ps_pkt->pkt;
 
-    if (p->ptrs.ip_api.is_valid())
+    if(p->ptrs.ip_api.is_ip())
     {
         if (p->ptrs.icmph)
         {
index 384cbca35ccf68f3a2f391d2266a687ac650039e..e71b052e87d81c39c4e38f63dc5685091899d003 100644 (file)
@@ -9,3 +9,4 @@ add_library (packet_io STATIC
     trough.cc
     trough.h
 )
+
index f2f96d72c04c2a1779866344dcf6d0c9db124d94..dd6610aca625c52d624d64f56b41c26f041192b8 100644 (file)
@@ -78,7 +78,7 @@ void Active_KillSession(Packet* p, EncodeFlags* pf)
 
     switch ( p->type() )
     {
-    case PktType::UNKNOWN:
+    case PktType::NONE:
         // Can only occur if we have never seen IP
         return;
 
@@ -390,7 +390,7 @@ static inline int _Active_DoReset(Packet* p)
     if ( !Active_IsEnabled() )
         return 0;
 
-    if ( !p->ptrs.ip_api.is_valid() )
+    if ( !p->ptrs.ip_api.is_ip() )
         return 0;
 
     switch ( p->type() )
index b2d43f813be2774118f826114e8e7c4e1c36aabc..03c31c921a7a12f9035a30b6d84e2ffad648270f 100644 (file)
@@ -338,10 +338,10 @@ int DAQ_SetFilter(const char* bpf)
     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();
index 1a41f28d89d90c309218d9a02df7f9ea1e4b62df..b33a43ca416ea2f72073682fe3a3085ea30cbc2b 100644 (file)
@@ -616,19 +616,22 @@ void config_alert_mode(SnortConfig* sc, const char* val)
         (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)
@@ -645,12 +648,13 @@ 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);
     }
 }
 
index 6d6fee21d4721304d964aac901bcdee7d38833ce..5e475ea7d1797aeaf38ea697b25c8f886665ae76 100644 (file)
 #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);
@@ -81,91 +85,189 @@ bool IpApi::set(const uint8_t* raw_ip_data)
         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;
 
@@ -175,42 +277,41 @@ static bool is_ip6_loopback(const snort_in6_addr* const ip)
         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
index 5b7a701a43e35bf733b08d032025f76c30badd39..782b88614714373ed0e0f3837ea82147989890e6 100644 (file)
@@ -49,14 +49,18 @@ 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.
@@ -67,7 +71,7 @@ public:
     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;
@@ -77,88 +81,64 @@ public:
     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
index cae4b5249240bb92f83c13c4e357465661e975cf..cce8f61067f9bdda8e3c481521ef81bbc84a2481 100644 (file)
@@ -171,7 +171,7 @@ struct SO_PUBLIC Packet
 
     /*  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(); }
@@ -237,6 +237,26 @@ struct SO_PUBLIC Packet
         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)
@@ -250,24 +270,6 @@ struct SO_PUBLIC Packet
 
 #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); }
 
index b2de3e28e03458eb506ebfbd1b9fa361dfa1aeff..a915dd8fc4edf7c35bdc889ac0ec2508c51e5403 100644 (file)
@@ -173,6 +173,13 @@ static_assert(CODEC_ENCAP_LAYER == (CODEC_UNSURE_ENCAP | CODEC_SAVE_LAYER),
     "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
 //-------------------------------------------------------------------------
@@ -184,9 +191,7 @@ void PacketManager::decode(
     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 )
@@ -373,7 +378,7 @@ static inline uint8_t GetTTL(const Packet* const p, bool forward)
 {
     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;
index 32abdac2648c479338024414b8eedafb32b6e0e0..8e5c081860d0a7acb8408ae4e0c2f226f1d6f92f 100644 (file)
@@ -1,5 +1,6 @@
 //--------------------------------------------------------------------------
 // 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
@@ -19,7 +20,6 @@
 *   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:
index 7c2b4fcd4d3cbfbe001bef0d07c86e763c1aef0e..356fb5e9906cbb0a87737f9897666bb5a2a891e0 100644 (file)
@@ -1,5 +1,6 @@
 //--------------------------------------------------------------------------
 // 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
@@ -19,7 +20,6 @@
 *   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:
index 123ec7a9049215d8aff1415e3353c6b57e032f91..883f7fdaec72f4f14d54605347688a4f75db3a28 100644 (file)
@@ -26,7 +26,7 @@
 **   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'
index 454b4f3c8d5b7857137e3d0632c8bfbcade777d7..2dfea3459e1ae773088899550b026baeaea778d2 100644 (file)
@@ -1,8 +1,8 @@
 //--------------------------------------------------------------------------
-// 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
@@ -31,7 +31,7 @@
 **   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:
index dbe61985d39c683c7a10eb7b5df09d3c7a9796e6..31fe33490bf97f1cc954848f9e891f6ec4a963de 100644 (file)
 ** 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
index f1c494bbbb3936582d42eda41f50176ef2890f3f..766b5ea00c5fe71a4b87ab7f7331b7b3b28736eb 100644 (file)
@@ -68,7 +68,7 @@ THREAD_LOCAL SimpleStats ftstats;
 
 static inline int InspectClientPacket(Packet* p)
 {
-    return PacketHasPAFPayload(p);
+    return p->has_paf_payload();
 }
 
 static int SnortFTP(
index e3b9d3964eef19406921c5a4f3987e11ba2485b6..70bfee5cc7309fe106dbc0b0fdd5414cce4e443b 100644 (file)
@@ -1079,7 +1079,7 @@ static int do_stateful_checks(FTP_SESSION* session, Packet* p,
                                 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;
@@ -1091,7 +1091,7 @@ static int do_stateful_checks(FTP_SESSION* session, Packet* p,
                                 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);
                             }
                         }
@@ -1151,7 +1151,7 @@ static int do_stateful_checks(FTP_SESSION* session, Packet* p,
                             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;
@@ -1163,7 +1163,7 @@ static int do_stateful_checks(FTP_SESSION* session, Packet* p,
                             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);
                         }
                     }
index aee9e6eca4d2c4ef942e1aae67a5b3fd54ce2e26..1a9a2e5b47848b5c4f681738ffee20f9228d2619 100644 (file)
@@ -2834,7 +2834,7 @@ int StatelessInspection(Packet* p, HI_SESSION* session, HttpSessionData* hsd, in
     {
         {
             /* 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 )
index 21b3db7c9523700504402eb21fad8f4650fcd168..8909db0b761637f888bbda921410899c205e6d52 100644 (file)
@@ -424,9 +424,9 @@ static inline FilePosition getFilePoistion(Packet* p)
 {
     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;
@@ -583,8 +583,7 @@ int HttpInspectMain(HTTPINSPECT_CONF* conf, Packet* p)
 
     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;
 
@@ -1074,7 +1073,7 @@ int HttpInspectMain(HTTPINSPECT_CONF* conf, Packet* p)
                     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))
index 7b455404c0b0dc49545489ab96fc8c4853a6b9bf..646eae321d0d3e9e56acdce8520f851dc2b29566 100644 (file)
@@ -78,7 +78,7 @@ int hi_mi_mode_inspection(HI_SESSION* session, int iInspectMode,
     */
     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;
index 192c630ea2f441d941d0533398ec6d48c2f5f742..d1333d9260fdb41d6ecf8629f69ac9cf58955ded 100644 (file)
@@ -1282,9 +1282,9 @@ static int HttpResponseInspection(HI_SESSION* session, Packet* p, const unsigned
     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 )
         {
@@ -1596,7 +1596,7 @@ static int HttpResponseInspection(HI_SESSION* session, Packet* p, const unsigned
 
                         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;
index 4d6212be20b633f4dc61ffc3278464b4fb0b0a11..765e8b83b3244adc41e3bc0bcb7f7d1c95bc91e5 100644 (file)
@@ -331,7 +331,9 @@ void HttpInspect::eval(Packet* p)
     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();
index c5b002cf8c86b7ad32bad2802b848abba1bbbe98..dace1ad8fdd6a3e00565e28855090ba7203f1516 100644 (file)
@@ -358,7 +358,7 @@ static void PrintImapConf(IMAP_PROTO_CONF* config)
 
 static inline int InspectPacket(Packet* p)
 {
-    return PacketHasPAFPayload(p);
+    return p->has_paf_payload();
 }
 
 static int IMAP_Setup(Packet* p, IMAPData* ssn)
index e17f306e03ca14166215648a05a5ec5347ed7173..6748425e339a78ec573685c35f306b92adc9bf89 100644 (file)
@@ -309,7 +309,7 @@ static void PrintPopConf(POP_PROTO_CONF* config)
 
 static inline int InspectPacket(Packet* p)
 {
-    return PacketHasPAFPayload(p);
+    return p->has_paf_payload();
 }
 
 static int POP_Setup(Packet* p, POPData* ssn)
index 3a1827f5787e5d7ad5d5a4895bcae49f2727b9f4..c7b22f719002d38edd304407482a4abf2f3f543d 100644 (file)
@@ -11,6 +11,8 @@ set( FILE_LIST
     smtp_config.h
     smtp_module.cc
     smtp_module.h
+    smtp_normalize.cc
+    smtp_normalize.h
 )
 
 if (STATIC_INSPECTORS)
index 8ec8e497e857ab2247be92c5b3108d7d9b9e6f3a..bfa45c27a0b11b30208bd3dcc68f3fd4bcbcb868 100644 (file)
@@ -653,7 +653,7 @@ static void SMTP_ResetState(void* ssn)
 
 static inline int InspectPacket(Packet* p)
 {
-    return PacketHasPAFPayload(p);
+    return p->has_paf_payload();
 }
 
 /*
index 3963a8b19b86a39c2afff28e969c259614ba4972..bb74ed6e231e9d902845c69a9131df8fdc0155d8 100644 (file)
@@ -26,10 +26,8 @@ using namespace std;
 #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"
@@ -43,6 +41,8 @@ struct WizStats
     PegCount tcp_hits;
     PegCount udp_scans;
     PegCount udp_hits;
+    PegCount user_scans;
+    PegCount user_hits;
 };
 
 const PegInfo wiz_pegs[] =
@@ -51,6 +51,8 @@ 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 }
 };
 
@@ -254,7 +256,7 @@ static const InspectApi wiz_api =
         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
index 262c0ce6aaa2645ff5397fbe3279d89dd345f7ef..42b7b9d248c29f26d61a0c7e14a5e1aecc94953a 100644 (file)
@@ -4,8 +4,11 @@ add_subdirectory(ip)
 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
 )
@@ -13,6 +16,7 @@ set (STREAM_INCLUDES
 add_library( stream STATIC
     flush_bucket.cc
     flush_bucket.h
+    paf.cc
     stream.h
     stream_api.cc
     stream_inspectors.cc
@@ -26,6 +30,8 @@ target_link_libraries( stream
     stream_icmp
     stream_tcp
     stream_udp
+    stream_user
+    stream_file
     protocols
 )
 
index e5a7b13b6cedd112a897ba63d4ac2dc177e1ff52..d6fd7fbad02f66a615d22cb68d51ff61fd204dc2 100644 (file)
@@ -6,12 +6,14 @@ noinst_LIBRARIES = libstream.a
 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 \
@@ -25,13 +27,17 @@ stream_splitter.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@
 
index fa2bd8e04b5d85f2ec21cf14e58ceb8b242daadb..d9eb52f1ba255b0cd6d55d5ef1ead99d14509b7b 100644 (file)
@@ -40,17 +40,23 @@ THREAD_LOCAL FlowControl* flow_con = nullptr;
 
 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;
@@ -58,14 +64,18 @@ static THREAD_LOCAL BaseStats t_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 }
 };
 
@@ -74,17 +84,23 @@ void base_sum()
     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);
@@ -160,6 +176,16 @@ void StreamBase::tinit()
     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)) )
@@ -170,28 +196,31 @@ void StreamBase::tinit()
         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*)
@@ -211,6 +240,16 @@ void StreamBase::eval(Packet* p)
 
     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);
@@ -224,14 +263,12 @@ void StreamBase::eval(Packet* 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:
@@ -292,7 +329,7 @@ static const InspectApi base_api =
         mod_dtor
     },
     IT_STREAM,
-    (unsigned)PktType::ANY_IP,
+    (unsigned)PktType::ANY_SSN,
     nullptr, // buffers
     nullptr, // service
     nullptr, // init
index 33b418666c09f81d4313c9174df1960c4ceedaac..b530e9d08ebccbabf621939c8fcfb54a919e9542 100644 (file)
@@ -34,6 +34,8 @@ static StreamModuleConfig stream_cfg =
     { 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
 };
 
 //-------------------------------------------------------------------------
index c8c22d5d3f93a46a1901c8d57535fbaf80eaadb8..20fa9bdc083171c8a0b3ba8cd501e05b4cf11bce 100644 (file)
@@ -41,6 +41,8 @@ struct StreamModuleConfig
     FlowConfig icmp_cfg;
     FlowConfig tcp_cfg;
     FlowConfig udp_cfg;
+    FlowConfig user_cfg;
+    FlowConfig file_cfg;
 };
 
 class StreamModule : public Module
diff --git a/src/stream/file/CMakeLists.txt b/src/stream/file/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5c3d912
--- /dev/null
@@ -0,0 +1,9 @@
+
+add_library( stream_file STATIC
+    file_module.cc
+    file_module.h
+    file_session.cc
+    file_session.h
+    stream_file.cc
+    stream_file.h
+)
diff --git a/src/stream/file/Makefile.am b/src/stream/file/Makefile.am
new file mode 100644 (file)
index 0000000..d3d2a16
--- /dev/null
@@ -0,0 +1,14 @@
+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@
+
diff --git a/src/stream/file/file_module.cc b/src/stream/file/file_module.cc
new file mode 100644 (file)
index 0000000..3a6f8bd
--- /dev/null
@@ -0,0 +1,70 @@
+//--------------------------------------------------------------------------
+// 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;
+}
+
diff --git a/src/stream/file/file_module.h b/src/stream/file/file_module.h
new file mode 100644 (file)
index 0000000..61cb2e6
--- /dev/null
@@ -0,0 +1,59 @@
+//--------------------------------------------------------------------------
+// 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
+
diff --git a/src/stream/file/file_session.cc b/src/stream/file/file_session.cc
new file mode 100644 (file)
index 0000000..9c705a7
--- /dev/null
@@ -0,0 +1,82 @@
+//--------------------------------------------------------------------------
+// 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;
+}
+
diff --git a/src/stream/file/file_session.h b/src/stream/file/file_session.h
new file mode 100644 (file)
index 0000000..9b9195c
--- /dev/null
@@ -0,0 +1,55 @@
+//--------------------------------------------------------------------------
+// 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
+
diff --git a/src/stream/file/stream_file.cc b/src/stream/file/stream_file.cc
new file mode 100644 (file)
index 0000000..6d040e5
--- /dev/null
@@ -0,0 +1,115 @@
+//--------------------------------------------------------------------------
+// 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;
+
diff --git a/src/stream/file/stream_file.h b/src/stream/file/stream_file.h
new file mode 100644 (file)
index 0000000..9f4c69c
--- /dev/null
@@ -0,0 +1,30 @@
+//--------------------------------------------------------------------------
+// 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
index 94c3544aea81b62b7bd8686926086983278c2340..d6f24bb298c052b04a76bb31f44fdb9f2d9b84be 100644 (file)
@@ -2180,7 +2180,7 @@ int Defrag::new_tracker(Packet* p, FragTracker* ft)
     {
         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));
@@ -2330,7 +2330,7 @@ int Defrag::add_frag_node(FragTracker* ft,
     {
         if (mem_in_use > FRAG_MEMCAP)
         {
-            flow_con->prune_flows(IPPROTO_IP, p);
+            flow_con->prune_flows(PktType::IP, p);
         }
 
         /*
@@ -2417,7 +2417,7 @@ int Defrag::dup_frag_node(
     {
         if (mem_in_use > FRAG_MEMCAP)
         {
-            flow_con->prune_flows(IPPROTO_IP, p);
+            flow_con->prune_flows(PktType::IP, p);
         }
 
         /*
index bc0e62cd9ed03cfb023a623424979733cfdbc1a9..72a6ffbd33db28b4f5ebd97f6eb4b9dcc48f02b1 100644 (file)
@@ -38,7 +38,7 @@ THREAD_LOCAL ProfileStats ip_perf_stats;
 // private methods
 //-------------------------------------------------------------------------
 
-void IpSessionCleanup(Flow* lws, FragTracker* tracker)
+static void IpSessionCleanup (Flow* lws, FragTracker* tracker)
 {
     if ( lws->ssn_server )
     {
@@ -119,7 +119,7 @@ void IpSession::clear()
     IpSessionCleanup(flow, &tracker);
 }
 
-bool IpSession::setup(Packet* p)
+bool IpSession::setup(Packet*)
 {
     DEBUG_WRAP(DebugMessage(DEBUG_STREAM,
         "Stream IP session created!\n"); );
@@ -127,9 +127,6 @@ bool IpSession::setup(Packet* p)
     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))
     {
@@ -148,7 +145,7 @@ int IpSession::process(Packet* p)
     if ( stream.expired_session(flow, p) )
     {
         IpSessionCleanup(flow, &tracker);
-        // FIXIT count ip sessionimeouts here
+        // FIXIT count ip session timeouts here
 
 #ifdef ENABLE_EXPECTED_IP
         if ( flow_con->expected_session(flow, p))
similarity index 88%
rename from src/stream/tcp/stream_paf.cc
rename to src/stream/paf.cc
index e5480636cc6c97735cd197a5a1904dfc9b87c136..de25a994b032283e7591b9a2c951f308a7727fa0 100644 (file)
 // 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"
@@ -60,7 +55,7 @@ static THREAD_LOCAL uint64_t prep_calls = 0;
 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
@@ -74,7 +69,7 @@ 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;
@@ -145,7 +140,7 @@ static int32_t s5_paf_flush(
 
 //--------------------------------------------------------------------
 
-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)
 {
@@ -167,7 +162,7 @@ static bool s5_paf_callback(
 
 //--------------------------------------------------------------------
 
-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)
 {
@@ -182,7 +177,7 @@ static inline bool s5_paf_eval(
     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;
 
@@ -223,12 +218,12 @@ static inline bool s5_paf_eval(
                 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;
@@ -247,21 +242,21 @@ static inline bool s5_paf_eval(
 // 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)
@@ -270,7 +265,7 @@ int32_t s5_paf_check(
         "%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;
@@ -283,7 +278,7 @@ int32_t s5_paf_check(
         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;
@@ -312,8 +307,8 @@ int32_t s5_paf_check(
     // 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
@@ -335,15 +330,12 @@ int32_t s5_paf_check(
         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 )
@@ -362,11 +354,8 @@ int32_t s5_paf_check(
 
     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;
similarity index 70%
rename from src/stream/tcp/stream_paf.h
rename to src/stream/paf.h
index dfcb705fbcad6cb8677cd4f252a1dde62c7af792..7838bb9b5df40e3872006fff13b968b506f61e63 100644 (file)
 //--------------------------------------------------------------------------
 
 //--------------------------------------------------------------------
-// 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"
@@ -34,8 +32,8 @@
 
 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
 {
@@ -48,35 +46,32 @@ 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);
index f14332b934ec51870cf93b6e63f4386468c7f38e..41313b5a6e60315166b05fa4a9b26b61271c2a58 100644 (file)
@@ -36,7 +36,7 @@
 #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"
@@ -62,6 +62,17 @@ Stream::Stream()
     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() { }
@@ -84,14 +95,14 @@ void Stream::delete_session(const FlowKey* key)
 //-------------------------------------------------------------------------
 
 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);
 }
@@ -108,9 +119,9 @@ void Stream::populate_session_key(Packet* p, FlowKey* 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,
@@ -141,16 +152,18 @@ FlowData* Stream::get_application_data_from_key(
 }
 
 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);
 }
@@ -175,9 +188,9 @@ void Stream::check_session_closed(Packet* p)
 }
 
 int Stream::ignore_session(
-    const sfip_tsrcIP, uint16_t srcPort,
-    const sfip_tdstIP, 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);
@@ -210,8 +223,7 @@ void Stream::stop_inspection(
     Flow* flow, Packet* p, char dir,
     int32_t /*bytes*/, int /*response*/)
 {
-    if (!flow)
-        return;
+    assert(flow && flow->session);
 
     switch (dir)
     {
@@ -229,14 +241,10 @@ void Stream::stop_inspection(
     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 */
@@ -387,9 +395,9 @@ void Stream::init_active_response(Packet* p, Flow* flow)
 //-------------------------------------------------------------------------
 
 int Stream::set_application_protocol_id_expected(
-    const sfip_tsrcIP, uint16_t srcPort,
-    const sfip_tdstIP, 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);
 
@@ -510,19 +518,23 @@ int16_t Stream::set_application_protocol_id(Flow* flow, int16_t id)
 // 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();
 }
 
 //-------------------------------------------------------------------------
@@ -728,24 +740,12 @@ void Stream::set_ip_protocol(Flow* flow)
 
 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;
 }
 
@@ -756,7 +756,7 @@ void Stream::flush_request(Packet* p)
 
     /* 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)
@@ -766,7 +766,7 @@ 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
@@ -794,99 +794,62 @@ int Stream::update_session_alert(
     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);
 }
 
index f0dfbd09efdccad18c52bceed7ca10ee56096911..c8087021e9d4978a95f724e21907c97e92c63816 100644 (file)
@@ -117,8 +117,8 @@ public:
      * 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.
      */
@@ -190,7 +190,7 @@ public:
      * 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
@@ -201,7 +201,7 @@ public:
      *      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
@@ -209,7 +209,7 @@ public:
      * 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
      *
@@ -228,9 +228,9 @@ public:
     // 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.
@@ -241,7 +241,7 @@ public:
      *     -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
@@ -252,7 +252,8 @@ public:
      *     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
@@ -276,7 +277,8 @@ public:
      *     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.
index db42b64f2671131966f91f3be158d65ee8da63dd..061e53b826c534062cb976b8d974de1f856cea42 100644 (file)
@@ -29,6 +29,11 @@ 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_stream_user;
+extern const BaseApi* nin_stream_file;
+
+extern const BaseApi* ips_stream_reassemble;
+extern const BaseApi* ips_stream_size;
 
 const BaseApi* stream_inspectors[] =
 {
@@ -37,6 +42,12 @@ 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
 };
 
index b9e85072931ed67e1b56205240e58a61215abc01..3293a04aa3cc8cffb43fc0f1c89204970bfa1166 100644 (file)
@@ -1,7 +1,5 @@
 
 add_library( stream_tcp STATIC
-    stream_paf.cc
-    stream_paf.h
     stream_tcp.cc
     stream_tcp.h
     tcp_module.cc
index db0bebb70c3c9675172297eba1a0d8203c8dd0f4..f610011877f4c638f8ddeb56f1a43a9d2425c112 100644 (file)
@@ -3,8 +3,6 @@ AUTOMAKE_OPTIONS=foreign no-dependencies
 noinst_LIBRARIES = libstream_tcp.a
 
 libstream_tcp_a_SOURCES = \
-stream_paf.cc \
-stream_paf.h \
 stream_tcp.cc \
 stream_tcp.h \
 tcp_module.cc \
index a12e777803216446de022a203f8b6638023c93bc..02127efe7bd034200de9da4188769bf2a63f8aa8 100644 (file)
@@ -65,37 +65,5 @@ void tcp_stats();
 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
 
index 0aa983184b5be4c1a7ac5cbedd8bea1cc6b6e39d..8cdd41613c5e810c5ceb34b32f556401e8c2be48 100644 (file)
@@ -335,15 +335,15 @@ Session* get_tcp_session(Flow* lwssn)
     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;
@@ -364,7 +364,7 @@ static inline uint32_t SegsToFlush(const StreamTracker* st, unsigned max)
     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 :(
@@ -387,22 +387,22 @@ static inline void SetupTcpDataBlock(TcpDataBlock*, Packet*);
 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*);
@@ -467,7 +467,7 @@ static THREAD_LOCAL Packet* s5_pkt = nullptr;
 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;
@@ -479,57 +479,7 @@ static inline void init_flush_policy(Flow*, StreamTracker* trk)
         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)
     {
@@ -771,9 +721,9 @@ static void PrintStateMgr(StateMgr* s)
     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);
@@ -809,9 +759,9 @@ static void PrintTcpSession(TcpSession* ts)
     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)
@@ -1231,14 +1181,8 @@ static inline int IsBetween(uint32_t low, uint32_t high, uint32_t cur)
     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;
 
@@ -1250,7 +1194,7 @@ static inline uint32_t StreamGetWindow(
     }
     // 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
@@ -1263,7 +1207,7 @@ static inline uint32_t StreamGetWindow(
 }
 
 // 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;
 }
@@ -1273,7 +1217,7 @@ static inline int ValidRstSynSent(StreamTracker* st, TcpDataBlock* tdb)
 // 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) && "
@@ -1339,8 +1283,8 @@ static inline int ValidRst(
 }
 
 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 )
@@ -1549,7 +1493,7 @@ static inline int ValidTimestamp(
 //                     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);
 
@@ -1575,7 +1519,7 @@ static inline int ValidSeq(
 
 #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;
@@ -1623,7 +1567,7 @@ static inline int ValidSeq(
 #endif
 
 static inline void UpdateSsn(
-    Packet*, StreamTracker* rcv, StreamTracker* snd, TcpDataBlock* tdb)
+    Packet*, TcpTracker *rcv, TcpTracker *snd, TcpDataBlock *tdb)
 {
 #if 0
     if (
@@ -1637,7 +1581,7 @@ static inline void UpdateSsn(
     {
         // 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?
@@ -1734,9 +1678,9 @@ static inline void SetupTcpDataBlock(TcpDataBlock* tdb, Packet* p)
 #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",
@@ -1753,10 +1697,10 @@ static void SegmentFree(StreamSegment* seg)
         "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,
@@ -1774,7 +1718,7 @@ static void DeleteSeglist(StreamSegment* listhead)
 }
 
 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;
@@ -1804,10 +1748,10 @@ static inline int purge_alerts(
     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;
 
@@ -1896,7 +1840,7 @@ static inline int purge_to_seq(TcpSession* tcpssn, StreamTracker* st, uint32_t f
     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;
@@ -1911,9 +1855,9 @@ static inline void purge_all(StreamTracker* st)
 //   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 )
@@ -1955,11 +1899,10 @@ static void ShowRebuiltPacket(TcpSession* ssn, Packet* pkt)
 }
 
 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;
 
@@ -1968,7 +1911,7 @@ static inline unsigned int getSegmentFlushSize(
         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;
@@ -1978,8 +1921,8 @@ static inline unsigned int getSegmentFlushSize(
  * 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_tflushbuf_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; );
@@ -1994,7 +1937,7 @@ static int FlushStream(
 
     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;
@@ -2081,7 +2024,7 @@ static int FlushStream(
 }
 
 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;
@@ -2236,7 +2179,7 @@ static inline int _flush_to_seq(
  * 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"); );
@@ -2294,7 +2237,7 @@ static inline int flush_to_seq(
  * 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;
 
@@ -2315,11 +2258,11 @@ static inline uint32_t get_q_footprint(StreamTracker* st)
 // 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;
@@ -2347,7 +2290,7 @@ static inline uint32_t get_q_sequenced(StreamTracker* st)
 }
 
 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);
@@ -2357,7 +2300,7 @@ static inline int flush_ackd(
 // 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 )
@@ -2372,145 +2315,7 @@ static inline int flush_stream(
     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()); );
@@ -2553,8 +2358,8 @@ static void TcpSessionClear(Flow* lwssn, TcpSession* tcpssn, int freeApplication
     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 )
@@ -2568,14 +2373,11 @@ static void TcpSessionClear(Flow* lwssn, TcpSession* tcpssn, int freeApplication
     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 )
@@ -2634,9 +2436,9 @@ static void TcpSessionCleanup(Flow* lwssn, int freeApplicationData, Packet* 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 )
@@ -2714,9 +2516,9 @@ static const char* const flushxt[] =
     "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;
 
@@ -2740,7 +2542,7 @@ static void TraceSegments(const StreamTracker* a)
 }
 
 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;
 
@@ -2777,8 +2579,8 @@ static void TraceTCP(
     )
 {
     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;
@@ -2787,34 +2589,36 @@ static void TraceTCP(
     {
         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);
     }
 }
 
@@ -2950,7 +2754,7 @@ static uint32_t StreamPacketHasWscale(Packet* p)
 }
 
 #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) );
 }
@@ -2959,8 +2763,8 @@ static inline int IsWellFormed(Packet* p, StreamTracker* ts)
 
 static void FinishServerInit(Packet* p, TcpDataBlock* tdb, TcpSession* ssn)
 {
-    StreamTracker* server;
-    StreamTracker* client;
+    TcpTracker *server;
+    TcpTracker *client;
 
     if (!ssn)
     {
@@ -3008,9 +2812,9 @@ static void FinishServerInit(Packet* p, TcpDataBlock* tdb, TcpSession* 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;
 
@@ -3052,7 +2856,7 @@ static void NewQueue(
     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,
@@ -3064,10 +2868,10 @@ static inline int SegmentFastTrack(StreamSegment* tail, TcpDataBlock* tdb)
     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 )
@@ -3084,10 +2888,10 @@ static inline StreamSegment* SegmentAlloc(
             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;
@@ -3100,16 +2904,16 @@ static inline StreamSegment* SegmentAlloc(
 }
 
 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)
@@ -3127,7 +2931,7 @@ static int AddStreamNode(
 
 #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); );
@@ -3218,12 +3022,10 @@ static int AddStreamNode(
     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;
@@ -3251,8 +3053,8 @@ static int DupStreamNode(Packet* p,
     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.
@@ -3271,25 +3073,20 @@ static inline bool IsRetransmit(StreamSegment* seg, const uint8_t* rdata,
 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;
@@ -3297,13 +3094,13 @@ static inline NormMode get_norm_ips(StreamTracker* st)
     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;
@@ -3322,7 +3119,7 @@ static int StreamQueue(StreamTracker* st, Packet* p, TcpDataBlock* tdb,
     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;
         );
@@ -3911,8 +3708,9 @@ right_overlap_last:
     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,
@@ -3926,7 +3724,7 @@ static void ProcessTcpStream(StreamTracker* rcv, TcpSession* tcpssn,
 #endif
 
     if ((config->flags & STREAM_CONFIG_NO_ASYNC_REASSEMBLY) &&
-        !TwoWayTraffic(tcpssn->flow))
+        !tcpssn->flow->two_way_traffic())
     {
         return;
     }
@@ -4027,8 +3825,8 @@ static void ProcessTcpStream(StreamTracker* rcv, TcpSession* tcpssn,
 }
 
 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);
@@ -4138,7 +3936,7 @@ static int ProcessTcpData(
     return STREAM_UNALIGNED;
 }
 
-void SetTcpReassemblyPolicy(StreamTracker* st)
+void SetTcpReassemblyPolicy(TcpTracker *st)
 {
     st->reassembly_policy = GetTcpReassemblyPolicy(st->os_policy);
 }
@@ -4166,7 +3964,7 @@ static void SetOSPolicy(Flow* flow, TcpSession* tcpssn)
  * 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;
 
@@ -4282,7 +4080,7 @@ static void NewTcpSession(
         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;
 
@@ -4295,7 +4093,7 @@ static void NewTcpSession(
             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 )
                 {
@@ -4614,8 +4412,8 @@ static void NewTcpSessionOnData(
 }
 
 static int RepeatedSyn(
-    StreamTracker* listener, StreamTracker* talker,
-    TcpDataBlock* tdb, TcpSession* tcpssn)
+    TcpTracker *listener, TcpTracker *talker,
+    TcpDataBlock *tdb, TcpSession *tcpssn)
 {
     switch (listener->os_policy)
     {
@@ -4746,10 +4544,10 @@ static int ProcessTcp(
     int got_ts = 0;
     int new_ssn = 0;
     int ts_action = ACTION_NOTHING;
-    TcpSessiontcpssn = 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)
@@ -5048,12 +4846,12 @@ static int ProcessTcp(
     {
         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;
@@ -5246,10 +5044,9 @@ static int ProcessTcp(
                 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;
@@ -5598,7 +5395,7 @@ static int ProcessTcp(
                     // 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(
@@ -5829,34 +5626,34 @@ static inline uint32_t GetForwardDir(const Packet* p)
 // 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);
 
@@ -5865,9 +5662,9 @@ static inline int32_t flush_pdu_ips(
             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;
@@ -5879,7 +5676,7 @@ static inline int32_t flush_pdu_ips(
     return -1;
 }
 
-static inline void fallback(StreamTracker* a)
+static inline void fallback(TcpTracker* a)
 {
     bool c2s = a->splitter->to_server();
 
@@ -5889,8 +5686,8 @@ static inline void fallback(StreamTracker* a)
 }
 
 static inline int CheckFlushPolicyOnData(
-    TcpSession* tcpssn, StreamTracker* talker,
-    StreamTracker* listener, Packet* p)
+    TcpSession *tcpssn, TcpTracker *talker,
+    TcpTracker *listener, Packet *p)
 {
     uint32_t flushed = 0;
 
@@ -5979,11 +5776,11 @@ static inline int CheckFlushPolicyOnData(
 // - 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);
@@ -5991,15 +5788,15 @@ static inline int32_t flush_pdu_ackd(
 
     // * 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;
@@ -6010,7 +5807,7 @@ static inline int32_t flush_pdu_ackd(
 
         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);
 
@@ -6029,7 +5826,7 @@ static inline int32_t flush_pdu_ackd(
                 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;
                 }
             }
@@ -6043,8 +5840,8 @@ static inline int32_t flush_pdu_ackd(
 }
 
 int CheckFlushPolicyOnAck(
-    TcpSession* tcpssn, StreamTracker* talker,
-    StreamTracker* listener, Packet* p)
+    TcpSession *tcpssn, TcpTracker *talker,
+    TcpTracker *listener, Packet *p)
 {
     uint32_t flushed = 0;
 
@@ -6110,8 +5907,8 @@ int CheckFlushPolicyOnAck(
     return flushed;
 }
 
-static void StreamSeglistAddNode(StreamTracker* st, StreamSegment* prev,
-    StreamSegment* ss)
+static void StreamSeglistAddNode(
+    TcpTracker *st, TcpSegment *prev, TcpSegment *ss)
 {
     tcpStats.segs_queued++;
 
@@ -6137,7 +5934,7 @@ static void StreamSeglistAddNode(StreamTracker* st, StreamSegment* prev,
     st->seg_count++;
 }
 
-static int StreamSeglistDeleteNode(StreamTracker* st, StreamSegment* seg)
+static int StreamSeglistDeleteNode (TcpTracker* st, TcpSegment* seg)
 {
     int ret;
     assert(st && seg);
@@ -6177,11 +5974,11 @@ static int StreamSeglistDeleteNode(StreamTracker* st, StreamSegment* 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;
@@ -6202,190 +5999,357 @@ static int StreamSeglistDeleteNodeTrim(
     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);
 
@@ -6408,28 +6372,26 @@ int StreamUpdateSessionAlertTcp(
     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);
@@ -6437,22 +6399,16 @@ void StreamClearExtraDataTcp(Flow* lwssn, Packet* p, uint32_t 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;
     }
@@ -6460,190 +6416,66 @@ char StreamGetReassemblyDirectionTcp(Flow* lwssn)
     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(
@@ -6651,7 +6483,7 @@ 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))
     {
@@ -6683,9 +6515,9 @@ void TcpSession::update_direction(
 #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));
 }
 
 /*
@@ -6716,9 +6548,8 @@ int TcpSession::process(Packet* p)
     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() )
@@ -6742,10 +6573,10 @@ int TcpSession::process(Packet* p)
                     "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);
@@ -6770,7 +6601,7 @@ midstream_pickup_allowed:
                 return 0;
             }
         }
-        tcpssn->lws_init = true;
+        lws_init = true;
     }
     /*
      * Check if the session is expired.
@@ -6823,12 +6654,56 @@ midstream_pickup_allowed:
 
 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()
index 507489b6f37a1a714824f7139a7caedff57ff31f..5e39ab6063dae2ee8789da22ec54445b8d741b9f 100644 (file)
@@ -21,7 +21,7 @@
 #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 */
@@ -55,7 +55,7 @@ struct StateMgr
 //
 // -- 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
 //-------------------------------------------------------------------------
@@ -72,19 +72,19 @@ struct StreamAlertInfo
 };
 
 //-----------------------------------------------------------------
-// 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;
@@ -113,31 +113,29 @@ enum FlushPolicy
     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
      */
@@ -169,10 +167,11 @@ struct StreamTracker
     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
@@ -186,24 +185,46 @@ public:
 
     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. */
diff --git a/src/stream/user/CMakeLists.txt b/src/stream/user/CMakeLists.txt
new file mode 100644 (file)
index 0000000..d7d0ca3
--- /dev/null
@@ -0,0 +1,9 @@
+
+add_library( stream_user STATIC
+    user_module.cc
+    user_module.h
+    user_session.cc
+    user_session.h
+    stream_user.cc
+    stream_user.h
+)
diff --git a/src/stream/user/Makefile.am b/src/stream/user/Makefile.am
new file mode 100644 (file)
index 0000000..59a6685
--- /dev/null
@@ -0,0 +1,14 @@
+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@
+
diff --git a/src/stream/user/stream_user.cc b/src/stream/user/stream_user.cc
new file mode 100644 (file)
index 0000000..5d63ae5
--- /dev/null
@@ -0,0 +1,148 @@
+//--------------------------------------------------------------------------
+// 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;
+
diff --git a/src/stream/user/stream_user.h b/src/stream/user/stream_user.h
new file mode 100644 (file)
index 0000000..b1d7499
--- /dev/null
@@ -0,0 +1,34 @@
+//--------------------------------------------------------------------------
+// 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
diff --git a/src/stream/user/user_module.cc b/src/stream/user/user_module.cc
new file mode 100644 (file)
index 0000000..b1bab6a
--- /dev/null
@@ -0,0 +1,91 @@
+//--------------------------------------------------------------------------
+// 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
+
diff --git a/src/stream/user/user_module.h b/src/stream/user/user_module.h
new file mode 100644 (file)
index 0000000..b1a20e8
--- /dev/null
@@ -0,0 +1,65 @@
+//--------------------------------------------------------------------------
+// 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
+
diff --git a/src/stream/user/user_session.cc b/src/stream/user/user_session.cc
new file mode 100644 (file)
index 0000000..e9b0764
--- /dev/null
@@ -0,0 +1,444 @@
+//--------------------------------------------------------------------------
+// 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; }
+
diff --git a/src/stream/user/user_session.h b/src/stream/user/user_session.h
new file mode 100644 (file)
index 0000000..5c3089c
--- /dev/null
@@ -0,0 +1,122 @@
+//--------------------------------------------------------------------------
+// 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
+
index 49c744103732aec75531546b9f663ee7c3652a99..2eccc472f7664492fd442c459ce98621bbc649f0 100644 (file)
@@ -299,7 +299,7 @@ HostAttributeEntry* SFAT_LookupHostEntryByIP(const sfip_t* ipAddr)
 
 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());
@@ -307,7 +307,7 @@ HostAttributeEntry* SFAT_LookupHostEntryBySrc(Packet* p)
 
 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());
index fe99b783b9a81acdee0470825fb9d6583908fec1..e87f876515e5c77c8a82aba46c476d14587c7021 100644 (file)
@@ -39,6 +39,7 @@
 #include "filters/sfthreshold.h"
 #include "time/ppm.h"
 #include "time/profiler.h"
+#include "file_api/file_service.h"
 
 #define STATS_SEPARATOR \
     "--------------------------------------------------"
@@ -158,6 +159,8 @@ static void timing_stats()
 // 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
@@ -184,7 +187,7 @@ 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" },
@@ -313,6 +316,9 @@ void DropStats()
     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");