From: Russ Combs Date: Sat, 16 May 2015 01:19:58 +0000 (-0400) Subject: russ: X-Git-Tag: 3.0.0-233~974 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bf83d76371c05245f3235a2d2ecb248b52a5da13;p=thirdparty%2Fsnort3.git russ: -- 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 --- diff --git a/.gitignore b/.gitignore index c8f3795bf..6056410cf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -*.[oac] +*.[oa] *.deps/ *.la *.libs/ diff --git a/ChangeLog b/ChangeLog index f8a9e229d..afea48406 100644 --- 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 diff --git a/configure.ac b/configure.ac index 6efe3e270..5ea639392 100644 --- a/configure.ac +++ b/configure.ac @@ -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 \ diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index a5e522a03..36b01aa45 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -39,6 +39,7 @@ set(BUILT_SOURCES ) set (UNBUILT_SOURCES + daq.txt differences.txt errors.txt enviro.txt diff --git a/doc/Makefile.am b/doc/Makefile.am index 07a200069..5d98af362 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -28,6 +28,7 @@ snort2lua_cmds.txt unbuilt_sources = \ snort_manual.txt \ config_changes.txt \ +daq.txt \ differences.txt \ enviro.txt \ errors.txt \ diff --git a/doc/config_changes.txt b/doc/config_changes.txt index b5c529227..641773862 100644 --- a/doc/config_changes.txt +++ b/doc/config_changes.txt @@ -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 index 000000000..7e40f81cc --- /dev/null +++ b/doc/daq.txt @@ -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 + ./snort -r + + ./snort --daq pcap --daq-mode passive -i + ./snort --daq pcap --daq-mode read-file -r + +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 + [--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=] \ + [--daq-var proto=] \ + [--daq-var queue=] + + ::= ip | eth0, etc; default is IP injection + ::= ip4 | ip6 |; default is ip4 + ::= 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[: ] + +Start the IPQ DAQ as follows: + + ./snort --daq ipq \ + [--daq-var device=] \ + [--daq-var proto=] \ + + ::= ip | eth0, etc; default is IP injection + ::= 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 + +Instead, start Snort like this: + + ./snort --daq ipfw [--daq-var 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 --daq dump + ./snort -r --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= + +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 -Q --daq dump --daq-var load-mode=read-file + ./snort -i -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 + [--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 [] [] + -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
+ +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=] [--daq-var proto=] [-Q] + + ::= 1..65535; default is 8000 + ::= 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 + $server + + $packet -> client + $packet -> server + + $packet -> + +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. + diff --git a/doc/snort_manual.txt b/doc/snort_manual.txt index d18d00a66..065c9a7c6 100644 --- a/doc/snort_manual.txt +++ b/doc/snort_manual.txt @@ -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[] diff --git a/extra/configure.ac b/extra/configure.ac index aee23fcd9..332601c7f 100644 --- a/extra/configure.ac +++ b/extra/configure.ac @@ -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 \ diff --git a/extra/src/CMakeLists.txt b/extra/src/CMakeLists.txt index bd6aa0b02..8552dcfaf 100644 --- a/extra/src/CMakeLists.txt +++ b/extra/src/CMakeLists.txt @@ -79,6 +79,7 @@ endif (BUILD_EXTRA_PLUGINS) add_subdirectory (codecs) +add_subdirectory (daqs) add_subdirectory (inspectors) add_subdirectory (ips_options) add_subdirectory (loggers) diff --git a/extra/src/Makefile.am b/extra/src/Makefile.am index 8481a3813..9f5851af3 100644 --- a/extra/src/Makefile.am +++ b/extra/src/Makefile.am @@ -2,6 +2,7 @@ AUTOMAKE_OPTIONS=foreign SUBDIRS = \ codecs \ +daqs \ inspectors \ ips_options \ loggers \ diff --git a/extra/src/codecs/CMakeLists.txt b/extra/src/codecs/CMakeLists.txt index d01f92d1e..6d921ea7d 100644 --- a/extra/src/codecs/CMakeLists.txt +++ b/extra/src/codecs/CMakeLists.txt @@ -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) diff --git a/extra/src/codecs/Makefile.am b/extra/src/codecs/Makefile.am index f9b3fe6bc..82f7a475f 100644 --- a/extra/src/codecs/Makefile.am +++ b/extra/src/codecs/Makefile.am @@ -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 index 000000000..94562731b --- /dev/null +++ b/extra/src/codecs/daq204.diff @@ -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=] [--daq-var proto=] [-Q] ++ ++ ::= 1..65535; default is 8000 ++ ::= 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 */ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#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 index 000000000..b12c0b459 --- /dev/null +++ b/extra/src/codecs/socket.cc @@ -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 + +#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& v) override; + bool decode(const RawData&, CodecData&, DecodeData&) override; +}; + +void SocketCodec::get_data_link_type(std::vector& 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 index 000000000..4dc9e7cc5 --- /dev/null +++ b/extra/src/daqs/CMakeLists.txt @@ -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 index 000000000..241cb3ab5 --- /dev/null +++ b/extra/src/daqs/Makefile.am @@ -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 index 000000000..1b5730fd2 --- /dev/null +++ b/extra/src/daqs/daq_file.c @@ -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 */ + +#include "daq_socket.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#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 index 000000000..e98f84d6e --- /dev/null +++ b/extra/src/daqs/daq_socket.c @@ -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 */ + +#include "daq_socket.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#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 index 000000000..5f7fc6e64 --- /dev/null +++ b/extra/src/daqs/daq_socket.h @@ -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 */ +/* this is a C include, not C++ */ + +#ifndef DAQ_AUX_H +#define DAQ_AUX_H + +#include + +/* 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 index 000000000..4203a2efb --- /dev/null +++ b/extra/src/daqs/daq_user.c @@ -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 */ + +#include "daq_socket.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#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 -> +// $packet -> client +// $packet -> server +// $client +// $server +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, +}; + diff --git a/extra/src/inspectors/data_log.cc b/extra/src/inspectors/data_log.cc index e76537eb9..49f498630 100644 --- a/extra/src/inspectors/data_log.cc +++ b/extra/src/inspectors/data_log.cc @@ -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() diff --git a/extra/src/loggers/CMakeLists.txt b/extra/src/loggers/CMakeLists.txt index bbe037765..a9592c9a9 100644 --- a/extra/src/loggers/CMakeLists.txt +++ b/extra/src/loggers/CMakeLists.txt @@ -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 diff --git a/extra/src/loggers/Makefile.am b/extra/src/loggers/Makefile.am index b4c2929a1..e5680f2f7 100644 --- a/extra/src/loggers/Makefile.am +++ b/extra/src/loggers/Makefile.am @@ -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 index 000000000..5c362c7d7 --- /dev/null +++ b/extra/src/loggers/log_user.cc @@ -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 + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +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 +}; + diff --git a/snort.pc.in b/snort.pc.in index a68135fa5..ad769317f 100644 --- a/snort.pc.in +++ b/snort.pc.in @@ -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@ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d5db97dfd..7a869e09a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -101,6 +101,8 @@ target_link_libraries( snort stream_icmp stream_tcp stream_udp + stream_user + stream_file http_inspect flow parser diff --git a/src/Makefile.am b/src/Makefile.am index eed74a744..f2ac16883 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/actions/act_react.cc b/src/actions/act_react.cc index c93dcb184..dcc39356e 100644 --- a/src/actions/act_react.cc +++ b/src/actions/act_react.cc @@ -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 diff --git a/src/actions/act_replace.cc b/src/actions/act_replace.cc index 36d1a77b2..656ca8d6a 100644 --- a/src/actions/act_replace.cc +++ b/src/actions/act_replace.cc @@ -150,7 +150,7 @@ ReplaceAction::ReplaceAction(ReplaceModule*) : void ReplaceAction::exec(Packet* p) { - if ( PacketIsRebuilt(p) ) + if ( p->is_rebuilt() ) return; Replace_ModifyPacket(p); diff --git a/src/codecs/ip/cd_esp.cc b/src/codecs/ip/cd_esp.cc index 3249d411a..3ec04eb29 100644 --- a/src/codecs/ip/cd_esp.cc +++ b/src/codecs/ip/cd_esp.cc @@ -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 diff --git a/src/codecs/ip/cd_gre.cc b/src/codecs/ip/cd_gre.cc index 25b54fe5f..3e5b6b2bd 100644 --- a/src/codecs/ip/cd_gre.cc +++ b/src/codecs/ip/cd_gre.cc @@ -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 diff --git a/src/codecs/ip/cd_icmp4.cc b/src/codecs/ip/cd_icmp4.cc index ce4008bfc..c5401d46a 100644 --- a/src/codecs/ip/cd_icmp4.cc +++ b/src/codecs/ip/cd_icmp4.cc @@ -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 diff --git a/src/codecs/ip/cd_icmp6.cc b/src/codecs/ip/cd_icmp6.cc index a6b86e464..9b623053e 100644 --- a/src/codecs/ip/cd_icmp6.cc +++ b/src/codecs/ip/cd_icmp6.cc @@ -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 diff --git a/src/codecs/ip/cd_ipv4.cc b/src/codecs/ip/cd_ipv4.cc index 24a4d1666..ceb90f276 100644 --- a/src/codecs/ip/cd_ipv4.cc +++ b/src/codecs/ip/cd_ipv4.cc @@ -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 diff --git a/src/codecs/ip/cd_ipv6.cc b/src/codecs/ip/cd_ipv6.cc index 48d966770..c26221990 100644 --- a/src/codecs/ip/cd_ipv6.cc +++ b/src/codecs/ip/cd_ipv6.cc @@ -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 diff --git a/src/codecs/ip/cd_pgm.cc b/src/codecs/ip/cd_pgm.cc index 6c065c99d..c6440529b 100644 --- a/src/codecs/ip/cd_pgm.cc +++ b/src/codecs/ip/cd_pgm.cc @@ -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 diff --git a/src/codecs/ip/cd_routing.cc b/src/codecs/ip/cd_routing.cc index 801368a97..68744478c 100644 --- a/src/codecs/ip/cd_routing.cc +++ b/src/codecs/ip/cd_routing.cc @@ -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 diff --git a/src/codecs/ip/cd_tcp.cc b/src/codecs/ip/cd_tcp.cc index 849d14274..9e3727b50 100644 --- a/src/codecs/ip/cd_tcp.cc +++ b/src/codecs/ip/cd_tcp.cc @@ -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 diff --git a/src/codecs/ip/cd_udp.cc b/src/codecs/ip/cd_udp.cc index dd3c7650b..41587b31e 100644 --- a/src/codecs/ip/cd_udp.cc +++ b/src/codecs/ip/cd_udp.cc @@ -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 diff --git a/src/codecs/link/cd_arp.cc b/src/codecs/link/cd_arp.cc index 64911d89a..091e0284e 100644 --- a/src/codecs/link/cd_arp.cc +++ b/src/codecs/link/cd_arp.cc @@ -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 diff --git a/src/codecs/link/cd_mpls.cc b/src/codecs/link/cd_mpls.cc index b257a1a38..49bc7daba 100644 --- a/src/codecs/link/cd_mpls.cc +++ b/src/codecs/link/cd_mpls.cc @@ -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 diff --git a/src/codecs/link/cd_ppp_encap.cc b/src/codecs/link/cd_ppp_encap.cc index dc5e01df4..4ae635661 100644 --- a/src/codecs/link/cd_ppp_encap.cc +++ b/src/codecs/link/cd_ppp_encap.cc @@ -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 diff --git a/src/codecs/link/cd_pppoe.cc b/src/codecs/link/cd_pppoe.cc index 306534e59..956e424a6 100644 --- a/src/codecs/link/cd_pppoe.cc +++ b/src/codecs/link/cd_pppoe.cc @@ -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 diff --git a/src/codecs/misc/CMakeLists.txt b/src/codecs/misc/CMakeLists.txt index 6425e338d..5488e95e3 100644 --- a/src/codecs/misc/CMakeLists.txt +++ b/src/codecs/misc/CMakeLists.txt @@ -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) diff --git a/src/codecs/misc/Makefile.am b/src/codecs/misc/Makefile.am index a3fe55a7c..d5a2f4d9e 100644 --- a/src/codecs/misc/Makefile.am +++ b/src/codecs/misc/Makefile.am @@ -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@ + diff --git a/src/codecs/misc/cd_gtp.cc b/src/codecs/misc/cd_gtp.cc index e836d105e..e966b5418 100644 --- a/src/codecs/misc/cd_gtp.cc +++ b/src/codecs/misc/cd_gtp.cc @@ -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 diff --git a/src/codecs/misc/cd_teredo.cc b/src/codecs/misc/cd_teredo.cc index 04be25a4b..13f49e74a 100644 --- a/src/codecs/misc/cd_teredo.cc +++ b/src/codecs/misc/cd_teredo.cc @@ -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 diff --git a/src/codecs/root/cd_eth.cc b/src/codecs/root/cd_eth.cc index 247d0a9dc..e3106a717 100644 --- a/src/codecs/root/cd_eth.cc +++ b/src/codecs/root/cd_eth.cc @@ -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 diff --git a/src/codecs/root/cd_wlan.cc b/src/codecs/root/cd_wlan.cc index 3d1335615..31f5b9985 100644 --- a/src/codecs/root/cd_wlan.cc +++ b/src/codecs/root/cd_wlan.cc @@ -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 diff --git a/src/detection/detect.cc b/src/detection/detect.cc index 387bbbb3b..ea979af91 100644 --- a/src/detection/detect.cc +++ b/src/detection/detect.cc @@ -1,7 +1,7 @@ //-------------------------------------------------------------------------- -// Copyright (C) 1998-2002 Martin Roesch // Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved. // Copyright (C) 2002-2013 Sourcefire, Inc. +// Copyright (C) 1998-2002 Martin Roesch // // 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; diff --git a/src/detection/fpdetect.cc b/src/detection/fpdetect.cc index afa668c7d..3058fb0fe 100644 --- a/src/detection/fpdetect.cc +++ b/src/detection/fpdetect.cc @@ -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 diff --git a/src/detection/tag.cc b/src/detection/tag.cc index f8889b2ed..3147a6845 100644 --- a/src/detection/tag.cc +++ b/src/detection/tag.cc @@ -1,7 +1,7 @@ //-------------------------------------------------------------------------- -// Copyright (C) 1998-2002 Martin Roesch // Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved. // Copyright (C) 2002-2013 Sourcefire, Inc. +// Copyright (C) 1998-2002 Martin Roesch // // 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; diff --git a/src/file_api/CMakeLists.txt b/src/file_api/CMakeLists.txt index e664efb35..8d9de1f73 100644 --- a/src/file_api/CMakeLists.txt +++ b/src/file_api/CMakeLists.txt @@ -15,3 +15,6 @@ add_library ( file_api STATIC file_mime_config.cc file_mime_config.h ) + +target_link_libraries(file_api file) + diff --git a/src/file_api/file_api.h b/src/file_api/file_api.h index 65186b116..267d9a18c 100644 --- a/src/file_api/file_api.h +++ b/src/file_api/file_api.h @@ -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); diff --git a/src/file_api/file_service.cc b/src/file_api/file_service.cc index ac9852f9b..7531f3d71 100644 --- a/src/file_api/file_service.cc +++ b/src/file_api/file_service.cc @@ -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" @@ -47,10 +48,16 @@ #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 - diff --git a/src/file_api/file_service.h b/src/file_api/file_service.h index 7f19c79bc..2cbe9f47d 100644 --- a/src/file_api/file_service.h +++ b/src/file_api/file_service.h @@ -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 diff --git a/src/file_api/libs/file_config.h b/src/file_api/libs/file_config.h index 6e4fe4f89..99ffe02d0 100644 --- a/src/file_api/libs/file_config.h +++ b/src/file_api/libs/file_config.h @@ -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; diff --git a/src/file_api/libs/file_identifier.cc b/src/file_api/libs/file_identifier.cc index edd11e7f0..ee0b73d75 100644 --- a/src/file_api/libs/file_identifier.cc +++ b/src/file_api/libs/file_identifier.cc @@ -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; } diff --git a/src/file_api/libs/file_lib.cc b/src/file_api/libs/file_lib.cc index 963ae163a..331fd8dfd 100644 --- a/src/file_api/libs/file_lib.cc +++ b/src/file_api/libs/file_lib.cc @@ -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 - diff --git a/src/file_api/libs/file_lib.h b/src/file_api/libs/file_lib.h index 057d1b0db..d84c4e103 100644 --- a/src/file_api/libs/file_lib.h +++ b/src/file_api/libs/file_lib.h @@ -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 diff --git a/src/filters/rate_filter.cc b/src/filters/rate_filter.cc index f8e443947..8bf44aa81 100644 --- a/src/filters/rate_filter.cc +++ b/src/filters/rate_filter.cc @@ -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(); diff --git a/src/flow/expect_cache.cc b/src/flow/expect_cache.cc index 6dce6d931..d3d4bb5f1 100644 --- a/src/flow/expect_cache.cc +++ b/src/flow/expect_cache.cc @@ -123,18 +123,18 @@ struct ExpectKey sfip_t ip2; uint16_t port1; uint16_t port2; - uint32_t protocol; + PktType protocol; bool set( - const sfip_t* cliIP, uint16_t cliPort, - const sfip_t* srvIP, uint16_t srvPort, - uint8_t proto); + const sfip_t *cliIP, uint16_t cliPort, + const sfip_t *srvIP, uint16_t srvPort, + PktType proto); }; inline bool ExpectKey::set( - const sfip_t* cliIP, uint16_t cliPort, - const sfip_t* srvIP, uint16_t srvPort, - uint8_t proto) + const sfip_t *cliIP, uint16_t cliPort, + const sfip_t *srvIP, uint16_t srvPort, + PktType proto ) { bool reverse; SFIP_RET rval = sfip_compare(cliIP, srvIP); @@ -155,7 +155,7 @@ inline bool ExpectKey::set( port2 = cliPort; reverse = true; } - protocol = static_cast(proto); + protocol = proto; return reverse; } @@ -343,9 +343,9 @@ ExpectCache::~ExpectCache () * session expiry in seconds. */ int ExpectCache::add_flow( - const sfip_t* cliIP, uint16_t cliPort, - const sfip_t* srvIP, uint16_t srvPort, - uint8_t protocol, char direction, + const sfip_t *cliIP, uint16_t cliPort, + const sfip_t *srvIP, uint16_t srvPort, + PktType protocol, char direction, FlowData* fd, int16_t appId) { assert(!cliPort || !srvPort); @@ -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; diff --git a/src/flow/expect_cache.h b/src/flow/expect_cache.h index b3ac54448..c9c8975d3 100644 --- a/src/flow/expect_cache.h +++ b/src/flow/expect_cache.h @@ -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*); diff --git a/src/flow/flow.cc b/src/flow/flow.cc index 7ff5c5506..40ce2a953 100644 --- a/src/flow/flow.cc +++ b/src/flow/flow.cc @@ -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()? diff --git a/src/flow/flow.h b/src/flow/flow.h index 15dde223f..c32c01cbe 100644 --- a/src/flow/flow.h +++ b/src/flow/flow.h @@ -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 diff --git a/src/flow/flow_control.cc b/src/flow/flow_control.cc index 411a0628e..67a515d63 100644 --- a/src/flow/flow_control.cc +++ b/src/flow/flow_control.cc @@ -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_t* srcIP, uint16_t srcPort, - const sfip_t* dstIP, uint16_t dstPort, - uint8_t protocol, char direction, + const sfip_t *srcIP, uint16_t srcPort, + const sfip_t *dstIP, uint16_t dstPort, + PktType protocol, char direction, FlowData* fd) { return exp_cache->add_flow( @@ -661,9 +806,9 @@ int FlowControl::add_expected( } int FlowControl::add_expected( - const sfip_t* srcIP, uint16_t srcPort, - const sfip_t* dstIP, uint16_t dstPort, - uint8_t protocol, int16_t appId, FlowData* fd) + const sfip_t *srcIP, uint16_t srcPort, + const sfip_t *dstIP, uint16_t dstPort, + PktType protocol, int16_t appId, FlowData* fd) { return exp_cache->add_flow( srcIP, srcPort, dstIP, dstPort, protocol, SSN_DIR_BOTH, fd, appId); diff --git a/src/flow/flow_control.h b/src/flow/flow_control.h index 41c731e3b..598197976 100644 --- a/src/flow/flow_control.h +++ b/src/flow/flow_control.h @@ -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_t* srcIP, uint16_t srcPort, - const sfip_t* dstIP, uint16_t dstPort, - uint8_t protocol, char direction, FlowData*); + const sfip_t *srcIP, uint16_t srcPort, + const sfip_t *dstIP, uint16_t dstPort, + PktType, char direction, FlowData*); int add_expected( - const sfip_t* srcIP, uint16_t srcPort, - const sfip_t* dstIP, uint16_t dstPort, - uint8_t protocol, int16_t appId, FlowData*); + const sfip_t *srcIP, uint16_t srcPort, + const sfip_t *dstIP, uint16_t dstPort, + PktType, int16_t appId, FlowData*); - uint32_t max_flows(uint8_t proto); + uint32_t max_flows(PktType); - PegCount get_prunes(uint8_t); - PegCount get_flows(uint8_t); + PegCount get_prunes(PktType); + PegCount get_flows(PktType); void clear_counts(); private: - class FlowCache* get_cache(uint8_t); + class FlowCache* get_cache(PktType); void set_key(FlowKey*, Packet*); unsigned process(Flow*, Packet*); private: + FlowCache* ip_cache; + FlowCache* icmp_cache; FlowCache* tcp_cache; FlowCache* udp_cache; - FlowCache* icmp_cache; - FlowCache* ip_cache; + FlowCache* user_cache; + FlowCache* file_cache; + Flow* ip_mem; + Flow* icmp_mem; Flow* tcp_mem; Flow* udp_mem; - Flow* icmp_mem; - Flow* ip_mem; + Flow* user_mem; + Flow* file_mem; + InspectSsnFunc get_ip; + InspectSsnFunc get_icmp; InspectSsnFunc get_tcp; InspectSsnFunc get_udp; - InspectSsnFunc get_icmp; - InspectSsnFunc get_ip; + InspectSsnFunc get_user; + InspectSsnFunc get_file; class ExpectCache* exp_cache; }; diff --git a/src/flow/flow_key.cc b/src/flow/flow_key.cc index dc5f00f34..42ef0fe8d 100644 --- a/src/flow/flow_key.cc +++ b/src/flow/flow_key.cc @@ -36,9 +36,10 @@ //------------------------------------------------------------------------- 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); } diff --git a/src/flow/flow_key.h b/src/flow/flow_key.h index e4585151f..77c4a2208 100644 --- a/src/flow/flow_key.h +++ b/src/flow/flow_key.h @@ -26,26 +26,27 @@ 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 diff --git a/src/flow/session.h b/src/flow/session.h index 6910507b5..add6ba69f 100644 --- a/src/flow/session.h +++ b/src/flow/session.h @@ -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; } diff --git a/src/framework/codec.h b/src/framework/codec.h index d24868818..283e6b5b4 100644 --- a/src/framework/codec.h +++ b/src/framework/codec.h @@ -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 { diff --git a/src/framework/decode_data.h b/src/framework/decode_data.h index ee1788f04..e7c1175dd 100644 --- a/src/framework/decode_data.h +++ b/src/framework/decode_data.h @@ -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 diff --git a/src/ips_options/ips_flow.cc b/src/ips_options/ips_flow.cc index 3e93e8c06..8eacc1b04 100644 --- a/src/ips_options/ips_flow.cc +++ b/src/ips_options/ips_flow.cc @@ -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; diff --git a/src/ips_options/ips_fragbits.cc b/src/ips_options/ips_fragbits.cc index b4eddcc1a..d96533c63 100644 --- a/src/ips_options/ips_fragbits.cc +++ b/src/ips_options/ips_fragbits.cc @@ -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; } diff --git a/src/ips_options/ips_pcre.cc b/src/ips_options/ips_pcre.cc index bff372b56..ae54161b8 100644 --- a/src/ips_options/ips_pcre.cc +++ b/src/ips_options/ips_pcre.cc @@ -1,8 +1,8 @@ //-------------------------------------------------------------------------- -// Copyright (C) 2003 Brian Caswell -// Copyright (C) 2003 Michael J. Pomraning // Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved. // Copyright (C) 2003-2013 Sourcefire, Inc. +// Copyright (C) 2003 Brian Caswell +// Copyright (C) 2003 Michael J. Pomraning // // 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 diff --git a/src/ips_options/ips_replace.cc b/src/ips_options/ips_replace.cc index 3261ff3de..3aeab276c 100644 --- a/src/ips_options/ips_replace.cc +++ b/src/ips_options/ips_replace.cc @@ -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") ) diff --git a/src/ips_options/ips_tos.cc b/src/ips_options/ips_tos.cc index 269a493ab..3adeac41d 100644 --- a/src/ips_options/ips_tos.cc +++ b/src/ips_options/ips_tos.cc @@ -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); diff --git a/src/ips_options/ips_ttl.cc b/src/ips_options/ips_ttl.cc index 9e4e12dfa..ea3a8ba75 100644 --- a/src/ips_options/ips_ttl.cc +++ b/src/ips_options/ips_ttl.cc @@ -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); diff --git a/src/log/log.cc b/src/log/log.cc index ddd993434..2fe993442 100644 --- a/src/log/log.cc +++ b/src/log/log.cc @@ -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); } diff --git a/src/log/log_text.cc b/src/log/log_text.cc index 04102462b..0f8ff649c 100644 --- a/src/log/log_text.cc +++ b/src/log/log_text.cc @@ -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)) { diff --git a/src/log/log_text.h b/src/log/log_text.h index a484b889e..0da2db3e5 100644 --- a/src/log/log_text.h +++ b/src/log/log_text.h @@ -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*); diff --git a/src/loggers/alert_fast.cc b/src/loggers/alert_fast.cc index 108fa9110..2162c2883 100644 --- a/src/loggers/alert_fast.cc +++ b/src/loggers/alert_fast.cc @@ -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 diff --git a/src/loggers/alert_sf_socket.cc b/src/loggers/alert_sf_socket.cc index 24a07abfd..8fe058287 100644 --- a/src/loggers/alert_sf_socket.cc +++ b/src/loggers/alert_sf_socket.cc @@ -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 diff --git a/src/loggers/alert_syslog.cc b/src/loggers/alert_syslog.cc index 2a927236b..a71d326cb 100644 --- a/src/loggers/alert_syslog.cc +++ b/src/loggers/alert_syslog.cc @@ -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) { diff --git a/src/loggers/unified2.cc b/src/loggers/unified2.cc index 7f2ab1208..d4cdcc89f 100644 --- a/src/loggers/unified2.cc +++ b/src/loggers/unified2.cc @@ -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); diff --git a/src/main/modules.cc b/src/main/modules.cc index 4d0160b9d..92547e87c 100644 --- a/src/main/modules.cc +++ b/src/main/modules.cc @@ -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") ) diff --git a/src/main/snort_config.h b/src/main/snort_config.h index 9f55c4a51..46eb97677 100644 --- a/src/main/snort_config.h +++ b/src/main/snort_config.h @@ -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 diff --git a/src/main/snort_module.cc b/src/main/snort_module.cc index 3ccee6f17..2069547a0 100644 --- a/src/main/snort_module.cc +++ b/src/main/snort_module.cc @@ -149,12 +149,12 @@ static const Parameter s_params[] = " to listen for telnet connections" }, #endif - { "-K", Parameter::PT_SELECT, "none|text|pcap", "none", - " logging mode" }, - { "-k", Parameter::PT_ENUM, "all|noip|notcp|noudp|noicmp|none", "all", " checksum mode (all,noip,notcp,noudp,noicmp,none)" }, + { "-L", Parameter::PT_STRING, nullptr, nullptr, + " logging mode (none, text, pcap, or log_*)" }, + { "-l", Parameter::PT_STRING, nullptr, nullptr, " 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()); diff --git a/src/managers/codec_manager.cc b/src/managers/codec_manager.cc index 9c9512182..f745a7557 100644 --- a/src/managers/codec_manager.cc +++ b/src/managers/codec_manager.cc @@ -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 diff --git a/src/managers/event_manager.cc b/src/managers/event_manager.cc index 52970fe57..b637d81d4 100644 --- a/src/managers/event_manager.cc +++ b/src/managers/event_manager.cc @@ -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); diff --git a/src/managers/inspector_manager.cc b/src/managers/inspector_manager.cc index 476de737d..3ac025d53 100644 --- a/src/managers/inspector_manager.cc +++ b/src/managers/inspector_manager.cc @@ -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; diff --git a/src/network_inspectors/binder/bind_module.cc b/src/network_inspectors/binder/bind_module.cc index b8d00bdd8..bb14af188 100644 --- a/src/network_inspectors/binder/bind_module.cc +++ b/src/network_inspectors/binder/bind_module.cc @@ -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()]; } diff --git a/src/network_inspectors/binder/binder.cc b/src/network_inspectors/binder/binder.cc index 677bfbfec..a0159363e 100644 --- a/src/network_inspectors/binder/binder.cc +++ b/src/network_inspectors/binder/binder.cc @@ -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 ) diff --git a/src/network_inspectors/network_inspectors.cc b/src/network_inspectors/network_inspectors.cc index 1fd098b69..7d8a1366f 100644 --- a/src/network_inspectors/network_inspectors.cc +++ b/src/network_inspectors/network_inspectors.cc @@ -26,16 +26,9 @@ 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 diff --git a/src/network_inspectors/normalize/normalize.cc b/src/network_inspectors/normalize/normalize.cc index bb91dfc7b..3154c861b 100644 --- a/src/network_inspectors/normalize/normalize.cc +++ b/src/network_inspectors/normalize/normalize.cc @@ -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); diff --git a/src/network_inspectors/perf_monitor/perf.cc b/src/network_inspectors/perf_monitor/perf.cc index 514bb8395..0fcfabf1b 100644 --- a/src/network_inspectors/perf_monitor/perf.cc +++ b/src/network_inspectors/perf_monitor/perf.cc @@ -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); diff --git a/src/network_inspectors/port_scan/port_scan.cc b/src/network_inspectors/port_scan/port_scan.cc index 2b015ab7a..26bf6c1d0 100644 --- a/src/network_inspectors/port_scan/port_scan.cc +++ b/src/network_inspectors/port_scan/port_scan.cc @@ -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 diff --git a/src/network_inspectors/port_scan/ps_detect.cc b/src/network_inspectors/port_scan/ps_detect.cc index 5e682ea6a..83e34cc7b 100644 --- a/src/network_inspectors/port_scan/ps_detect.cc +++ b/src/network_inspectors/port_scan/ps_detect.cc @@ -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) { diff --git a/src/packet_io/CMakeLists.txt b/src/packet_io/CMakeLists.txt index 384cbca35..e71b052e8 100644 --- a/src/packet_io/CMakeLists.txt +++ b/src/packet_io/CMakeLists.txt @@ -9,3 +9,4 @@ add_library (packet_io STATIC trough.cc trough.h ) + diff --git a/src/packet_io/active.cc b/src/packet_io/active.cc index f2f96d72c..dd6610aca 100644 --- a/src/packet_io/active.cc +++ b/src/packet_io/active.cc @@ -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() ) diff --git a/src/packet_io/sfdaq.cc b/src/packet_io/sfdaq.cc index b2d43f813..03c31c921 100644 --- a/src/packet_io/sfdaq.cc +++ b/src/packet_io/sfdaq.cc @@ -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(); diff --git a/src/parser/config_file.cc b/src/parser/config_file.cc index 1a41f28d8..b33a43ca4 100644 --- a/src/parser/config_file.cc +++ b/src/parser/config_file.cc @@ -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); } } diff --git a/src/protocols/ip.cc b/src/protocols/ip.cc index 6d6fee21d..5e475ea7d 100644 --- a/src/protocols/ip.cc +++ b/src/protocols/ip.cc @@ -20,54 +20,58 @@ #include #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(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(ip4h) + ip4h->hlen(); - - if (ip6h) - return reinterpret_cast(ip6h) + ip6h->hlen(); - + switch ( type ) + { + case IAT_4: return reinterpret_cast(iph) + ((IP4Hdr*)iph)->hlen(); + case IAT_6: return reinterpret_cast(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 diff --git a/src/protocols/ip.h b/src/protocols/ip.h index 5b7a701a4..782b88614 100644 --- a/src/protocols/ip.h +++ b/src/protocols/ip.h @@ -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(ip4h) + IP4_HEADER_LEN : nullptr; } + { return (type == IAT_4) ? reinterpret_cast(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 diff --git a/src/protocols/packet.h b/src/protocols/packet.h index cae4b5249..cce8f6106 100644 --- a/src/protocols/packet.h +++ b/src/protocols/packet.h @@ -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); } diff --git a/src/protocols/packet_manager.cc b/src/protocols/packet_manager.cc index b2de3e28e..a915dd8fc 100644 --- a/src/protocols/packet_manager.cc +++ b/src/protocols/packet_manager.cc @@ -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; diff --git a/src/search_engines/ac_bnfa.cc b/src/search_engines/ac_bnfa.cc index 32abdac26..8e5c08186 100644 --- a/src/search_engines/ac_bnfa.cc +++ b/src/search_engines/ac_bnfa.cc @@ -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 * * Updates: diff --git a/src/search_engines/ac_bnfa_q.cc b/src/search_engines/ac_bnfa_q.cc index 7c2b4fcd4..356fb5e99 100644 --- a/src/search_engines/ac_bnfa_q.cc +++ b/src/search_engines/ac_bnfa_q.cc @@ -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 * * Updates: diff --git a/src/search_engines/acsmx.cc b/src/search_engines/acsmx.cc index 123ec7a90..883f7fdae 100644 --- a/src/search_engines/acsmx.cc +++ b/src/search_engines/acsmx.cc @@ -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' diff --git a/src/search_engines/acsmx2.cc b/src/search_engines/acsmx2.cc index 454b4f3c8..2dfea3459 100644 --- a/src/search_engines/acsmx2.cc +++ b/src/search_engines/acsmx2.cc @@ -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: diff --git a/src/search_engines/bnfa_search.cc b/src/search_engines/bnfa_search.cc index dbe61985d..31fe33490 100644 --- a/src/search_engines/bnfa_search.cc +++ b/src/search_engines/bnfa_search.cc @@ -117,7 +117,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 ** ** 12/4/06 - man - modified summary ** 6/26/07 - man - Added last_match tracking, and accounted for nocase/case by diff --git a/src/service_inspectors/ftp_telnet/ftp.cc b/src/service_inspectors/ftp_telnet/ftp.cc index f1c494bbb..766b5ea00 100644 --- a/src/service_inspectors/ftp_telnet/ftp.cc +++ b/src/service_inspectors/ftp_telnet/ftp.cc @@ -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( diff --git a/src/service_inspectors/ftp_telnet/pp_ftp.cc b/src/service_inspectors/ftp_telnet/pp_ftp.cc index e3b9d3964..70bfee5cc 100644 --- a/src/service_inspectors/ftp_telnet/pp_ftp.cc +++ b/src/service_inspectors/ftp_telnet/pp_ftp.cc @@ -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); } } diff --git a/src/service_inspectors/http_inspect/hi_client.cc b/src/service_inspectors/http_inspect/hi_client.cc index aee9e6eca..1a9a2e5b4 100644 --- a/src/service_inspectors/http_inspect/hi_client.cc +++ b/src/service_inspectors/http_inspect/hi_client.cc @@ -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 ) diff --git a/src/service_inspectors/http_inspect/hi_main.cc b/src/service_inspectors/http_inspect/hi_main.cc index 21b3db7c9..8909db0b7 100644 --- a/src/service_inspectors/http_inspect/hi_main.cc +++ b/src/service_inspectors/http_inspect/hi_main.cc @@ -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)) diff --git a/src/service_inspectors/http_inspect/hi_mi.cc b/src/service_inspectors/http_inspect/hi_mi.cc index 7b455404c..646eae321 100644 --- a/src/service_inspectors/http_inspect/hi_mi.cc +++ b/src/service_inspectors/http_inspect/hi_mi.cc @@ -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; diff --git a/src/service_inspectors/http_inspect/hi_server.cc b/src/service_inspectors/http_inspect/hi_server.cc index 192c630ea..d1333d926 100644 --- a/src/service_inspectors/http_inspect/hi_server.cc +++ b/src/service_inspectors/http_inspect/hi_server.cc @@ -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; diff --git a/src/service_inspectors/http_inspect/http_inspect.cc b/src/service_inspectors/http_inspect/http_inspect.cc index 4d6212be2..765e8b83b 100644 --- a/src/service_inspectors/http_inspect/http_inspect.cc +++ b/src/service_inspectors/http_inspect/http_inspect.cc @@ -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(); diff --git a/src/service_inspectors/imap/imap.cc b/src/service_inspectors/imap/imap.cc index c5b002cf8..dace1ad8f 100644 --- a/src/service_inspectors/imap/imap.cc +++ b/src/service_inspectors/imap/imap.cc @@ -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) diff --git a/src/service_inspectors/pop/pop.cc b/src/service_inspectors/pop/pop.cc index e17f306e0..6748425e3 100644 --- a/src/service_inspectors/pop/pop.cc +++ b/src/service_inspectors/pop/pop.cc @@ -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) diff --git a/src/service_inspectors/smtp/CMakeLists.txt b/src/service_inspectors/smtp/CMakeLists.txt index 3a1827f57..c7b22f719 100644 --- a/src/service_inspectors/smtp/CMakeLists.txt +++ b/src/service_inspectors/smtp/CMakeLists.txt @@ -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) diff --git a/src/service_inspectors/smtp/smtp.cc b/src/service_inspectors/smtp/smtp.cc index 8ec8e497e..bfa45c27a 100644 --- a/src/service_inspectors/smtp/smtp.cc +++ b/src/service_inspectors/smtp/smtp.cc @@ -653,7 +653,7 @@ static void SMTP_ResetState(void* ssn) static inline int InspectPacket(Packet* p) { - return PacketHasPAFPayload(p); + return p->has_paf_payload(); } /* diff --git a/src/service_inspectors/wizard/wizard.cc b/src/service_inspectors/wizard/wizard.cc index 3963a8b19..bb74ed6e2 100644 --- a/src/service_inspectors/wizard/wizard.cc +++ b/src/service_inspectors/wizard/wizard.cc @@ -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 diff --git a/src/stream/CMakeLists.txt b/src/stream/CMakeLists.txt index 262c0ce6a..42b7b9d24 100644 --- a/src/stream/CMakeLists.txt +++ b/src/stream/CMakeLists.txt @@ -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 ) diff --git a/src/stream/Makefile.am b/src/stream/Makefile.am index e5a7b13b6..d6fd7fbad 100644 --- a/src/stream/Makefile.am +++ b/src/stream/Makefile.am @@ -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@ diff --git a/src/stream/base/stream_base.cc b/src/stream/base/stream_base.cc index fa2bd8e04..d9eb52f1b 100644 --- a/src/stream/base/stream_base.cc +++ b/src/stream/base/stream_base.cc @@ -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 diff --git a/src/stream/base/stream_module.cc b/src/stream/base/stream_module.cc index 33b418666..b530e9d08 100644 --- a/src/stream/base/stream_module.cc +++ b/src/stream/base/stream_module.cc @@ -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 }; //------------------------------------------------------------------------- diff --git a/src/stream/base/stream_module.h b/src/stream/base/stream_module.h index c8c22d5d3..20fa9bdc0 100644 --- a/src/stream/base/stream_module.h +++ b/src/stream/base/stream_module.h @@ -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 index 000000000..5c3d9122d --- /dev/null +++ b/src/stream/file/CMakeLists.txt @@ -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 index 000000000..d3d2a1604 --- /dev/null +++ b/src/stream/file/Makefile.am @@ -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 index 000000000..3a6f8bd31 --- /dev/null +++ b/src/stream/file/file_module.cc @@ -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 + +#include "file_module.h" + +#include +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 index 000000000..61cb2e6dd --- /dev/null +++ b/src/stream/file/file_module.h @@ -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 + +#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 index 000000000..9c705a7da --- /dev/null +++ b/src/stream/file/file_session.cc @@ -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 + +#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 index 000000000..9b9195c09 --- /dev/null +++ b/src/stream/file/file_session.h @@ -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 + +#ifndef USER_SESSION_H +#define USER_SESSION_H + +#include +#include + +#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 index 000000000..6d040e568 --- /dev/null +++ b/src/stream/file/stream_file.cc @@ -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 + +#include "stream_file.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#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 index 000000000..9f4c69c0d --- /dev/null +++ b/src/stream/file/stream_file.h @@ -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 + +#ifndef STREAM_FILE_H +#define STREAM_FILE_H + +struct StreamFileConfig +{ + bool upload; +}; + +StreamFileConfig* get_file_cfg(class Inspector*); + +#endif diff --git a/src/stream/ip/ip_defrag.cc b/src/stream/ip/ip_defrag.cc index 94c3544ae..d6f24bb29 100644 --- a/src/stream/ip/ip_defrag.cc +++ b/src/stream/ip/ip_defrag.cc @@ -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); } /* diff --git a/src/stream/ip/ip_session.cc b/src/stream/ip/ip_session.cc index bc0e62cd9..72a6ffbd3 100644 --- a/src/stream/ip/ip_session.cc +++ b/src/stream/ip/ip_session.cc @@ -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 sessiont imeouts here + // FIXIT count ip session timeouts here #ifdef ENABLE_EXPECTED_IP if ( flow_con->expected_session(flow, p)) diff --git a/src/stream/tcp/stream_paf.cc b/src/stream/paf.cc similarity index 88% rename from src/stream/tcp/stream_paf.cc rename to src/stream/paf.cc index e5480636c..de25a994b 100644 --- a/src/stream/tcp/stream_paf.cc +++ b/src/stream/paf.cc @@ -17,14 +17,9 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- -//-------------------------------------------------------------------- -// s5 stuff -// -// @file stream_paf.c -// @author Russ Combs -//-------------------------------------------------------------------- +// paf.cc author Russ Combs -#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; diff --git a/src/stream/tcp/stream_paf.h b/src/stream/paf.h similarity index 70% rename from src/stream/tcp/stream_paf.h rename to src/stream/paf.h index dfcb705fb..7838bb9b5 100644 --- a/src/stream/tcp/stream_paf.h +++ b/src/stream/paf.h @@ -18,14 +18,12 @@ //-------------------------------------------------------------------------- //-------------------------------------------------------------------- -// s5 protocol aware flushing stuff -// -// @file stream_paf.h -// @author Russ Combs +// protocol aware flushing stuff +// paf.h author Russ Combs //-------------------------------------------------------------------- -#ifndef STREAM_PAF_H -#define STREAM_PAF_H +#ifndef PAF_H +#define PAF_H #include #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); diff --git a/src/stream/stream_api.cc b/src/stream/stream_api.cc index f14332b93..41313b5a6 100644 --- a/src/stream/stream_api.cc +++ b/src/stream/stream_api.cc @@ -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_t* srcIP, uint16_t srcPort, - const sfip_t* dstIP, uint16_t dstPort, - uint8_t protocol, char direction, + const sfip_t *srcIP, uint16_t srcPort, + const sfip_t *dstIP, uint16_t dstPort, + PktType protocol, char direction, uint32_t flow_id) { assert(flow_con); @@ -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_t* srcIP, uint16_t srcPort, - const sfip_t* dstIP, uint16_t dstPort, - uint8_t protocol, int16_t appId, FlowData* fd) + const sfip_t *srcIP, uint16_t srcPort, + const sfip_t *dstIP, uint16_t dstPort, + PktType protocol, int16_t appId, FlowData* fd) { assert(flow_con); @@ -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); } diff --git a/src/stream/stream_api.h b/src/stream/stream_api.h index f0dfbd09e..c8087021e 100644 --- a/src/stream/stream_api.h +++ b/src/stream/stream_api.h @@ -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. diff --git a/src/stream/stream_inspectors.cc b/src/stream/stream_inspectors.cc index db42b64f2..061e53b82 100644 --- a/src/stream/stream_inspectors.cc +++ b/src/stream/stream_inspectors.cc @@ -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 }; diff --git a/src/stream/tcp/CMakeLists.txt b/src/stream/tcp/CMakeLists.txt index b9e850729..3293a04aa 100644 --- a/src/stream/tcp/CMakeLists.txt +++ b/src/stream/tcp/CMakeLists.txt @@ -1,7 +1,5 @@ add_library( stream_tcp STATIC - stream_paf.cc - stream_paf.h stream_tcp.cc stream_tcp.h tcp_module.cc diff --git a/src/stream/tcp/Makefile.am b/src/stream/tcp/Makefile.am index db0bebb70..f61001187 100644 --- a/src/stream/tcp/Makefile.am +++ b/src/stream/tcp/Makefile.am @@ -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 \ diff --git a/src/stream/tcp/stream_tcp.h b/src/stream/tcp/stream_tcp.h index a12e77780..02127efe7 100644 --- a/src/stream/tcp/stream_tcp.h +++ b/src/stream/tcp/stream_tcp.h @@ -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 diff --git a/src/stream/tcp/tcp_session.cc b/src/stream/tcp/tcp_session.cc index 0aa983184..8cdd41613 100644 --- a/src/stream/tcp/tcp_session.cc +++ b/src/stream/tcp/tcp_session.cc @@ -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_t* flushbuf_end) + Packet* p, TcpTracker *st, uint32_t toSeq, uint8_t *flushbuf, + const uint8_t *flushbuf_end) { uint16_t bytes_flushed = 0; STREAM_DEBUG_WRAP(uint32_t bytes_queued = st->seg_bytes_logical; ); @@ -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; - TcpSession* tcpssn = NULL; - StreamTracker* talker = NULL; - StreamTracker* listener = NULL; - STREAM_DEBUG_WRAP(char* t = NULL; char* l = NULL; ) + TcpSession *tcpssn = NULL; + TcpTracker *talker = NULL; + TcpTracker *listener = NULL; + STREAM_DEBUG_WRAP(char *t = NULL; char *l = NULL;) PROFILE_VARS; if (lwssn->protocol != PktType::TCP) @@ -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; ialert_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() diff --git a/src/stream/tcp/tcp_session.h b/src/stream/tcp/tcp_session.h index 507489b6f..5e39ab606 100644 --- a/src/stream/tcp/tcp_session.h +++ b/src/stream/tcp/tcp_session.h @@ -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 index 000000000..d7d0ca36b --- /dev/null +++ b/src/stream/user/CMakeLists.txt @@ -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 index 000000000..59a6685f3 --- /dev/null +++ b/src/stream/user/Makefile.am @@ -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 index 000000000..5d63ae58c --- /dev/null +++ b/src/stream/user/stream_user.cc @@ -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 + +#include "stream_user.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#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 index 000000000..b1d749900 --- /dev/null +++ b/src/stream/user/stream_user.h @@ -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 + +#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 index 000000000..b1bab6ab2 --- /dev/null +++ b/src/stream/user/user_module.cc @@ -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 + +#include "user_module.h" + +#include +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 index 000000000..b1a20e8e1 --- /dev/null +++ b/src/stream/user/user_module.h @@ -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 + +#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 index 000000000..e9b076492 --- /dev/null +++ b/src/stream/user/user_session.cc @@ -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 + +#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 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 index 000000000..5c3089c2a --- /dev/null +++ b/src/stream/user/user_session.h @@ -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 + +#ifndef USER_SESSION_H +#define USER_SESSION_H + +#include +#include + +#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 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 + diff --git a/src/target_based/sftarget_reader.cc b/src/target_based/sftarget_reader.cc index 49c744103..2eccc472f 100644 --- a/src/target_based/sftarget_reader.cc +++ b/src/target_based/sftarget_reader.cc @@ -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()); diff --git a/src/utils/stats.cc b/src/utils/stats.cc index fe99b783b..e87f87651 100644 --- a/src/utils/stats.cc +++ b/src/utils/stats.cc @@ -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");